Сканирование двухуровневого сайта, нужны комментарии в новых строках - PullRequest
0 голосов
/ 04 февраля 2020

Я очень плохо знаком с веб-очисткой, и я пытаюсь очистить этот онлайн-форум: https://community.whattoexpect.com/forums/postpartum-depression.html

Это двухуровневый сайт, где главная страница представляет собой список обсуждений, и вы можете нажать на каждое сообщение, чтобы получить полное содержание и увидеть комментарии комментариев. Основной сайт также имеет нумерацию страниц.

Я хочу, чтобы мой последний CSV выглядел примерно так:

enter image description here

Идея состоит в том, чтобы основной пост в одном ряду, а затем ответы в следующих строках. Я буду использовать один и тот же идентификатор для основного сообщения и ответов, чтобы их можно было связать.

Вот мой паук Scrapy:

import scrapy
import datetime

class PeripartumSpider(scrapy.Spider):
    name = 'peripartum'

    start_urls = ['http://www.community.whattoexpect.com/forums/postpartum-depression.html']

    def parse(self, response):
        for post_link in response.xpath('//*[@id="group-discussions"]/div[3]/div/div/a/@href').extract():
            link = response.urljoin(post_link)
            yield scrapy.Request(link, callback=self.parse_thread)

        # Checks if the main page has a link to next page if True keep parsing.
        next_page = response.xpath('(//a[@class="page-link"])[1]/@href').extract_first()
        if next_page:
            yield scrapy.Request(next_page, callback=self.parse)

        # Going into each post and extracting information.

    def parse_thread(self, response):
        original_post = response.xpath("//*[@class='__messageContent fr-element fr-view']/p/text()").extract()
        title = response.xpath("//*[@class='discussion-original-post__title']/text()").extract_first()
        author_name = response.xpath("//*[@class='discussion-original-post__author__name']/text()").extract_first()
        unixtime = response.xpath("//*[@class='discussion-original-post__author__updated']/@data-date").extract_first()
        unixtime = int(unixtime) / 1000  # Removing milliseconds
        timestamp = datetime.datetime.utcfromtimestamp(unixtime).strftime("%m/%d/%Y %H:%M")
        replies_list = response.xpath("//*[@class='discussion-replies__list']").getall()

        # Getting the comments and their information for each post

        reply_post = response.xpath(".//*[@class='wte-reply__content__message __messageContent fr-element fr-view']/p/text()").extract()
        reply_author = response.xpath("//*[@class='wte-reply__author__name']/text()").extract()
        reply_time = response.xpath("//*[@class='wte-reply__author__updated']/@data-date").extract()
        for reply in reply_time:
            reply_date = int(reply_time) / 1000  # Removing milliseconds
            reply_timestamp = datetime.datetime.utcfromtimestamp(reply_date).strftime("%m/%d/%Y %H:%M")

        yield {
            "title": title,
            "author_name": author_name,
            "time": timestamp,
            "post": original_post,
            "reply_author": reply_author,
            "reply_timestamp": reply_timestamp,
            "replies": reply_post
        }

Когда я пытаюсь запустить своего паука Я получаю 0 обходов. Я не уверен, правильно ли я следую за ссылками на каждый пост. И нужно ли использовать что-то вроде CSV-библиотеки Python, чтобы комментарии загружались в следующую строку, но с исходным идентификатором записи?

1 Ответ

0 голосов
/ 06 февраля 2020

Вы должны позаботиться о

  • существующей структуре документа веб-страницы
  • и вашей структуре кода, анализирующей содержимое

Может произойти лучше кодирование, чем следующее, просто идентифицируя n комментариев и после этого зацикливаясь на комментариях. В этом случае вам не нужно zip списки вместе. Но вы можете использовать его в качестве отправной точки

import scrapy
import datetime

class PeripartumSpider(scrapy.Spider):
    name = 'peripartum'

    start_urls = ['https://community.whattoexpect.com/forums/postpartum-depression.html']

    def parse(self, response):
        for post_link in response.xpath('//*[@id="group-discussions"]/div[3]/div/div/a/@href').extract():
            link = response.urljoin(post_link)
            yield scrapy.Request(link, callback=self.parse_thread)

        # Checks if the main page has a link to next page if True keep parsing.
        next_page = response.xpath('(//a[@class="page-link"])[1]/@href').extract_first()
        if next_page:
            yield scrapy.Request(next_page, callback=self.parse)

        # Going into each post and extracting information.

    def parse_thread(self, response):
        original_post = response.xpath("//*[@class='__messageContent fr-element fr-view']/p/text()").extract()
        title = response.xpath("//*[@class='discussion-original-post__title']/text()").extract_first()
        author_name = response.xpath("//*[@class='discussion-original-post__author__name']/text()").extract_first()
        unixtime = response.xpath("//*[@class='discussion-original-post__author__updated']/@data-date").extract_first()
        unixtime = int(unixtime) / 1000  # Removing milliseconds
        timestamp = datetime.datetime.utcfromtimestamp(unixtime).strftime("%m/%d/%Y %H:%M")
        replies_list = response.xpath("//*[@class='discussion-replies__list']").getall()

        # Getting the comments and their information for each post
        replies_post = response.xpath(".//*[@class='wte-reply__content__message __messageContent fr-element fr-view']/p/text()").extract()
        replies_author = response.xpath("//*[@class='wte-reply__author__name']/text()").extract()
        replies_time = response.xpath("//*[@class='wte-reply__author__updated']/@data-date").extract()
        replies = zip(replies_post, replies_author, replies_time)

        for reply_post, reply_author, reply_time in replies:
            reply_date = int(reply_time) / 1000  # Removing milliseconds
            reply_timestamp = datetime.datetime.utcfromtimestamp(reply_date).strftime("%m/%d/%Y %H:%M")
            yield {
                "title": title,
                "author_name": author_name,
                "time": timestamp,
                "post": original_post,
                "reply_author": reply_author,
                "reply_timestamp": reply_timestamp,
                "replies": reply_post
            }

Возможно, вам также придется позаботиться о разбиении на страницы в комментариях.

...