Извлечение общедоступных постов со страницы Facebook без API / ключа приложения / токена / секрета - PullRequest
0 голосов
/ 18 января 2019

Просто чтобы уточнить, у меня нет учетной записи Facebook, и я не собираюсь ее создавать.Кроме того, то, что я пытаюсь достичь, совершенно законно в моей стране.

Вместо того, чтобы использовать API Facebook для получения последних сообщений о времени на странице Facebook, я хочу отправить запрос на получение напрямую на страницу.URL (например, эта страница ) и извлечение сообщений из исходного кода HTML.
(Я хотел бы получить текст и время создания сообщения.)

КогдаЯ запускаю это в веб-консоли:

document.getElementsByClassName('userContent')

Я получаю список элементов, содержащих текст последних сообщений.

Но я бы хотел извлечь эту информацию из скрипта nodejs.Я мог бы сделать это довольно легко, используя браузер без головы, такой как puppeteer или подобный, но это создаст массу ненужных накладных расходов.Мне бы очень хотелось использовать простой подход, такой как загрузка кода HTML, передача его в cheerio и использование jQuery-подобного API cheeriio для извлечения сообщений.

Вот моя попытка попробовать именно это:

// npm i request cheerio request-promise-native
const rp = require('request-promise-native'); // requires installation of `request`
const cheerio = require('cheerio');

rp.get('https://www.facebook.com/pg/officialstackoverflow/posts/').then( postsHtml => {
    const $ = cheerio.load(postsHtml);

    const timeLinePostEls = $('.userContent');
    console.log(timeLinePostEls.html()); // should NOT be null
    const newestPostEl = timeLinePostEls.get(0);
    console.log(newestPostEl.html()); // should NOT be null
    const newestPostText = newestPostEl.text();
    console.log(newestPostText);
    //const newestPostTime = newestPostEl.parent(??).child('.livetimestamp').title;
    //console.log(newestPostTime);
}).catch(console.error);

к сожалению $('.userContent') не работает.Тем не менее, я смог убедиться, что данные, которые я ищу, встроены где-то в этот HTML-код.

Но я не мог придумать хороший подход к регулярным выражениям или тому подобное, чтобы извлечь этоdata.

В зависимости от содержимого сообщения количество тегов HTML в сообщении сильно варьируется.

Вот простой пример поста, содержащего одну ссылку:

<div class="_5pbx userContent _3576" data-ft="&#123;&quot;tn&quot;:&quot;K&quot;&#125;"><p>We&#039;re proud to be named one of Built In NYC&#039;s Best Places to Work in 2019, ranking in the top 10 for Best Midsize Places to Work and top 3 (!) for Best Perks and Benefits. See what it took to make the list and check out our profile to see some of our job openings. <a href="https://l.facebook.com/l.php?u=https%3A%2F%2Fbit.ly%2F2H3Kbr2&amp;h=AT29h2HyDsEk0rHRWqJA-Fa4M1qi3nJT1NBi95othaR3qeFuFAMNiVS2Dgtv5KR5m0xqjw6kfwZdhZt0_D3UQT1Oel2UhxRql-KwkA1xqWvrql4u1jDhzrkGVT_XxoUd8_w8_fzLZzzhz23a8yPCK6IPfWKB76_CEFjG3b78y4dFJvY9Z08AYlR01dmi5_FvWVEVytkN-123u6alYE8pqL6Jb6dtIQUTWGXYJPaNMrtxkCUZniEVXEcILkwHGSuHqCTAarboyMP55F1vhYO3OAiVMkvjbN274fVq92YvbK3bi90bU9T-5ADWHDUJ-CwcofSBTW47chstQeY0n_UluD_rBIPLsfXVSnCtpRkR2kXi9zzHLnNeIYeNssv3i7UKS_f5Z2pnVT6xe3zJbNpB68doH1Z__I9nsTCNIyFyKx2VxabecoL03DIawbRrzBoxLAwzNPLACBjTkpEQhdVn4_wdAIjXRL4cLQDcZkLEoG_sspBgRePH23TFbNufQOBly-FNtLHnkUDO2Ca-FYvAGXpcu6J4B1aH3XFPB803lsz-GRdACyOFOgXDXJfwr4WtWzUHxfiOPULWiI43yI5L4aU6wYRhPjxua3RuRZ8oj9fXa1w4Jrht94Ue2wfKtz8" target="_blank" data-ft="&#123;&quot;tn&quot;:&quot;-U&quot;&#125;" rel="noopener nofollow" data-lynx-mode="async">http://*******/2H3Kbr2</a></p></div>

Отформатированный в более читаемой форме, он выглядит примерно так:

<div class="_5pbx userContent _3576" data-ft="&#123;&quot;tn&quot;:&quot;K&quot;&#125;">
    <p>
        We&#039;re proud to be named one of Built In NYC&#039;s Best Places to Work in 
        2019, ranking in the top 10 for Best Midsize Places to Work and top 3 (!) for 
        Best Perks and Benefits. See what it took to make the list and check out our 
        profile to see some of our job openings.
        <a href="VERY_LONG_URL.........." target="_blank" data-ft="&#123;&quot;tn&quot;:&quot;-U&quot;&#125;" rel="noopener nofollow" data-lynx-mode="async">SHORT_LINK.....</a>
    </p>
</div>

Это регулярное выражение кажется, что работает нормально, но я не думаю, что это очень надежно:

/<div class="[^"]+ userContent [^"]+" data-ft="[^"]+">(.+?)<\/div>/g

Если, например, сообщение содержало другой элемент div, то оно не будет работать должным образом.В дополнение к этому у меня нет никакого способа узнать время / дату, когда пост был создан с использованием этого подхода?

Есть идеи, как я могу относительно надежно извлечь самые последние 2-3 поста, включая дату / время создания?

1 Ответ

0 голосов
/ 19 января 2019

Хорошо, я наконец понял это. Я надеюсь, что это будет полезно для других. Эта функция извлечет 20 последних сообщений, включая время создания:

// npm i request cheerio request-promise-native
const rp = require('request-promise-native'); // requires installation of `request`
const cheerio = require('cheerio');

function GetFbPosts(pageUrl) {
    const requestOptions = {
        url: pageUrl,
        headers: {
            'User-Agent': 'Mozilla/5.0 (X11; Fedora; Linux x86_64; rv:64.0) Gecko/20100101 Firefox/64.0'
        }
    };
    return rp.get(requestOptions).then( postsHtml => {
        const $ = cheerio.load(postsHtml);
        const timeLinePostEls = $('.userContent').map((i,el)=>$(el)).get();
        const posts = timeLinePostEls.map(post=>{
            return {
                message: post.html(),
                created_time: post.parents('.userContentWrapper').find('.timestampContent').html()
            }
        });
        return posts;
    });
}
GetFbPosts('https://www.facebook.com/pg/officialstackoverflow/posts/').then(posts=>{
    // Log all posts
    for (const post of posts) {
        console.log(post.created_at, post.message);
    }
});

Поскольку сообщения Facebook могут иметь сложное форматирование, сообщение представляет собой не простой текст, а HTML. Но вы можете удалить форматирование и просто получить текст, заменив message: post.html() на message: post.text().

...