Post comments on Facebook page via console

前端 未结 5 1146
说谎
说谎 2021-02-06 04:10

Like in the image, the Facebook comment box has no submit button, when you write something and press Enter button, the comment posted.

I want to submit the comment via J

5条回答
  •  悲哀的现实
    2021-02-06 04:37

    Some years after, this post remains relevant and is actually the only one I found regarding this, whilst I was toying around trying to post to FB groups through JS code (a task similar to the original question).

    At long last I cracked it - tested and works:

      setTimeout(() => {
            document.querySelector('[placeholder^="Write something"]').click();
            setTimeout(() => {
                let postText = "I'm a Facebook post from Javascript!";
                let dataDiv = document.querySelector('[contenteditable] [data-offset-key]');
                let dataKey = dataDiv.attributes["data-offset-key"].value;
                //Better to construct the span structure exactly in the form FB does it
                let spanHTML = `${postText}`;
                dataDiv.innerHTML = spanHTML;
    
                let eventType = "input";
                //This can probably be optimized, no need to fire events for so many elements
                let div = document.querySelectorAll('div[role=presentation]')[1].parentElement.parentElement;
                let collection = div.getElementsByTagName("*");
                [...collection].forEach(elem => {
                    let evt = document.createEvent("HTMLEvents");
                    evt.initEvent(eventType, true, true); //second "true" is for bubbling - might be important
                    elem.dispatchEvent(evt);
                });
                //Clicking the post button
                setTimeout(()=>{
                    document.querySelector('.rfloat button[type=submit][value="1"]').click();
                },2000);
            }, 4000);
        }, 7000);
    

    So here's the story, as I've learned from previous comments in this post and from digging into FB's code. FB uses React, thus changes to the DOM would not "catch on" as React uses virtual DOM. If you were to click "Post" after changing the DOM from JS, the text would not be posted. That's why you'd have to fire the events manually as was suggested here.

    However - firing the right event for the right element is tricky business and has almost prevented me from succeeding. After some long hours I found that this code works, probably because it targets multiple elements, starting from a parent element of the group post, and drilling down to all child elements and firing the event for each one of them (this is the [...collection].forEach(elem => { bit). As written this can be obviously be optimized to find the one right element that needs to fire the event.

    As for which event to fire, as was discussed here, I've experimented with several, and found "input" to be the one. Also, the code started working after I changed the second argument of initEvent to true - i.e. evt.initEvent(eventType, true, true). Not sure if this made a difference but I've had enough hours fiddling with this, if it works, that enough for me. BTW the setTimeouts can be played around with, of course.

    (Unsuccessfully) Digging into FB's React Data Structure

    Another note about a different path I tried to go and ended up being fruitless: using React Dev Tools Chrome extension, you're able to access the components themselves and all their props and states using $r. Surprisingly, this also works outside of the console, so using something like TamperMonkey to run JS code also works. I actually found where FB keeps the post text in the state. For reference, it's in a component called ComposerStatusAttachmentMentionsInputContainer that's in charge of the editor part of the post, and below is the code to access it.

    $r actually provides access to a lot of React stuff, like setState. Theoritically I believed I could use that to set the state of the post text in React (if you know React, you'd agree that setState would be the right way to trigger a change that would stick).

    However, after some long hours I found that this is VERY hard to do, since FB uses a framework on top of React called Draft.js, which handles all posts. This framework has it's own methods, classes, data structures and what not, and it's very hard to operate on those from "outside" without the source code.

    I also tried manually firing the onchange functions attached to the components, which didn't work because I didn't have the right parameters, which are objects in the likes of editorContent and selectionContent from Draft.Js, which need to be carefully constructed using methods like Modifier from Draft.js that I didn't have access to (how the hell do you externally access a static method from a library entangled in the source code?? I didn't manage to).

    Anyway, the code for accessing the state variable where the text is stored, provided you have React dev tools and you've highlighted ComposerStatusAttachmentMentionsInputContainer:

    let blockMap = $r["state"].activeEditorState["$1"].currentContent.blockMap;
    let innerObj = JSON.parse(JSON.stringify(blockMap)); //this is needed to get the next property as it's not static or something
    
    let id = Object.keys(innerObj)[0]; //get the id from the obj property 
    console.log(innerObj[id].text); //this is it!
    

    But as I wrote, this is pretty much useless :-)

提交回复
热议问题