【问题标题】:Using scrapy recursivelly for scrape a phpBB forum递归使用 scrapy 来抓取 phpBB 论坛
【发布时间】:2016-01-06 15:09:49
【问题描述】:

我正在尝试使用 scrapy 来抓取基于 phpbb 的论坛。我的scrapy知识水平非常基础(但正在提高)。

提取论坛帖子首页的内容或多或少很容易。我成功的刮板是这样的:

import scrapy

from ptmya1.items import Ptmya1Item

class bastospider3(scrapy.Spider):
    name = "basto3"
    allowed_domains = ["portierramaryaire.com"]
    start_urls = [
        "http://portierramaryaire.com/foro/viewtopic.php?f=3&t=3821&st=0&sk=t&sd=a"
    ]

    def parse(self, response):
        for sel in response.xpath('//div[2]/div'):
            item = Ptmya1Item()
            item['author'] = sel.xpath('div/div[1]/p/strong/a/text()').extract()
            item['date'] = sel.xpath('div/div[1]/p/text()').extract()
            item['body'] = sel.xpath('div/div[1]/div/text()').extract()
            yield item

但是,当我尝试使用“下一页”链接进行爬网时,我经历了很多令人沮丧的小时后失败了。我想向您展示我的尝试,以征求意见。 注意:我希望获得 SgmlLinkExtractor 变体的解决方案,因为它们更灵活、更强大,但经过多次尝试后,我优先考虑成功

第一个,路径受限的 SgmlLinkExtractor。 '下一页 xpath' 是

/html/body/div[1]/div[2]/form[1]/fieldset/a

确实,我用shell测试过

response.xpath('//div[2]/form[1]/fieldset/a/@href')[1].extract()

为“下一页”链接返回正确的值。但是,我想指出,引用的 xpath 提供 TWO 链接

 >>> response.xpath('//div[2]/form[1]/fieldset/a/@href').extract()
[u'./search.php?sid=5aa2b92bec28a93c85956e83f2f62c08', u'./viewtopic.php?f=3&t=3821&st=0&sk=t&sd=a&sid=5aa2b92bec28a93c85956e83f2f62c08&start=15']

因此,我的 失败刮刀

import scrapy
from scrapy.contrib.spiders import CrawlSpider, Rule
from scrapy.contrib.linkextractors.sgml import SgmlLinkExtractor
from scrapy.selector import HtmlXPathSelector

from ptmya1.items import Ptmya1Item

class bastospider3(scrapy.Spider):
    name = "basto7"
    allowed_domains = ["portierramaryaire.com"]
    start_urls = [
        "http://portierramaryaire.com/foro/viewtopic.php?f=3&t=3821&st=0&sk=t&sd=a"
    ]

    rules = (
            Rule(SgmlLinkExtractor(allow=(), restrict_xpaths=('//div[2]/form[1]/fieldset/a/@href')[1],), callback="parse_items", follow= True)
            )

    def parse_item(self, response):
        for sel in response.xpath('//div[2]/div'):
            item = Ptmya1Item()
            item['author'] = sel.xpath('div/div[1]/p/strong/a/text()').extract()
            item['date'] = sel.xpath('div/div[1]/p/text()').extract()
            item['body'] = sel.xpath('div/div[1]/div/text()').extract()
            yield item

第二个,允许的 SgmlLinkExtractor。更原始也更不成功

import scrapy
from scrapy.contrib.spiders import CrawlSpider, Rule
from scrapy.contrib.linkextractors.sgml import SgmlLinkExtractor
from scrapy.selector import HtmlXPathSelector

from ptmya1.items import Ptmya1Item

class bastospider3(scrapy.Spider):
    name = "basto7"
    allowed_domains = ["portierramaryaire.com"]
    start_urls = [
        "http://portierramaryaire.com/foro/viewtopic.php?f=3&t=3821&st=0&sk=t&sd=a"
    ]

    rules = (
            Rule(SgmlLinkExtractor(allow=(r'viewtopic.php?f=3&t=3821&st=0&sk=t&sd=a&start.',),), callback="parse_items", follow= True)
            )

    def parse_item(self, response):
        for sel in response.xpath('//div[2]/div'):
            item = Ptmya1Item()
            item['author'] = sel.xpath('div/div[1]/p/strong/a/text()').extract()
            item['date'] = sel.xpath('div/div[1]/p/text()').extract()
            item['body'] = sel.xpath('div/div[1]/div/text()').extract()
            yield item

最后,我回到了该死的旧石器时代,或者说是第一个教程。我尝试使用初学者教程末尾包含的循环。又一次失败

import scrapy
import urlparse

from ptmya1.items import Ptmya1Item

class bastospider5(scrapy.Spider):
    name = "basto5"
    allowed_domains = ["portierramaryaire.com"]
    start_urls = [
        "http://portierramaryaire.com/foro/viewtopic.php?f=3&t=3821&st=0&sk=t&sd=a"
    ]

    def parse_articles_follow_next_page(self, response):
        item = Ptmya1Item()
        item['cacho'] = response.xpath('//div[2]/form[1]/fieldset/a/@href').extract()[1][1:] + "http://portierramaryaire.com/foro"
        for sel in response.xpath('//div[2]/div'):
            item['author'] = sel.xpath('div/div[1]/p/strong/a/text()').extract()
            item['date'] = sel.xpath('div/div[1]/p/text()').extract()
            item['body'] = sel.xpath('div/div[1]/div/text()').extract()
            yield item

        next_page = response.xpath('//fieldset/a[@class="right-box right"]')
        if next_page:
           cadenanext = response.xpath('//div[2]/form[1]/fieldset/a/@href').extract()[1][1:]
           url = urlparse.urljoin("http://portierramaryaire.com/foro",cadenanext)
           yield scrapy.Request(url, self.parse_articles_follow_next_page)

所有情况中,我得到的是一个神秘的错误消息,我无法从中获得解决问题的提示。

2015-10-08 21:24:46 [scrapy] DEBUG: Crawled (200) <GET http://portierramaryaire.com/foro/viewtopic.php?f=3&t=3821&st=0&sk=t&sd=a> (referer: None)
2015-10-08 21:24:46 [scrapy] ERROR: Spider error processing <GET http://portierramaryaire.com/foro/viewtopic.php?f=3&t=3821&st=0&sk=t&sd=a> (referer: None)
Traceback (most recent call last):
  File "/usr/lib/python2.7/dist-packages/twisted/internet/defer.py", line 577, in _runCallbacks
    current.result = callback(current.result, *args, **kw)
  File "/usr/local/lib/python2.7/dist-packages/scrapy/spiders/__init__.py", line 76, in parse
    raise NotImplementedError
NotImplementedError
2015-10-08 21:24:46 [scrapy] INFO: Closing spider (finished)

对于这个问题,我真的很感激任何建议(或者更好的可行解决方案)。我完全坚持这一点,无论我读了多少,我都找不到解决方案:(

【问题讨论】:

    标签: python-2.7 xpath web-scraping scrapy screen-scraping


    【解决方案1】:

    因为这是 5 年的历史 - 很多很多新方法都在那里。

    顺便说一句:见https://github.com/Dascienz/phpBB-forum-scraper

    用于 phpBB 论坛的基于 Python 的网络爬虫。项目可以用作 用于构建您自己的自定义 Scrapy 蜘蛛或一次性的模板 在指定的论坛上爬行。请记住,侵略性 爬网会对网络服务器产生很大的压力,所以请 限制您的请求率。

    phpBB.py 蜘蛛从论坛中抓取以下信息 帖子:用户名用户帖子计数帖子日期和时间帖子文本引用文本 如果您需要抓取其他数据,则必须创建 额外的蜘蛛或编辑现有的蜘蛛。

    编辑 phpBB.py 并指定:allowed_domains start_urls username & 密码 forum_login=False 或 forum_login=True

    另见

    import requests
    forum = "the forum name"
    
    headers = {'User-Agent': 'Mozilla/5.0'}
    payload = {'username': 'username', 'password': 'password', 'redirect':'index.php', 'sid':'', 'login':'Login'}
    session = requests.Session()
    
    r = session.post(forum + "ucp.php?mode=login", headers=headers, data=payload)
    print(r.text)
    

    但请稍等:我们可以 - 而不是使用请求来操纵网站, 还利用浏览器自动化,如 mechanize 提供此功能。 这样我们就不必管理自己的会话,只需几行代码来制作每个请求。

    GitHub 上有一个有趣的例子https://github.com/winny-/sirsi/blob/317928f23847f4fe85e2428598fbe44c4dae2352/sirsi/sirsi.py#L74-L211

    【讨论】:

      【解决方案2】:

      感谢GHajba,问题解决了。解决方案是根据评论制定的。

      但是,蜘蛛不会按顺序返回结果。它开始于http://portierramaryaire.com/foro/viewtopic.php?f=3&t=3821&st=0&sk=t&sd=a

      它应该遍历“下一页”网址,如下所示:http://portierramaryaire.com/foro/viewtopic.php?f=3&t=3821&st=0&sk=t&sd=a&start=15

      每次增加 15 个帖子的“开始”变量。

      确实,蜘蛛首先返回产生'start=15'的页面,然后是'start=30',然后是'start=0',然后是'start=15',然后是'start=45'...

      我不确定我是否必须创建一个新问题,或者将来的读者在这里提出问题是否会更好。你怎么看?

      【讨论】:

        【解决方案3】:

        出现神秘错误消息是因为您没有使用parse 方法。这是 scrapy 在解析响应时的默认入口点。

        但是,您只定义了 parse_articles_follow_next_pageparse_item 函数——这绝对不是 parse 函数。

        这不是因为下一个站点,而是第一个站点:Scrapy 无法解析start_url,因此无论如何您的尝试都达不到。尝试将您的 parse_items 更改为 parse 并再次执行您的方法旧石器时代解决方案

        如果您使用的是Rule,那么您需要使用不同的蜘蛛。对于那些使用 CrawlSpider 的人,您可以在教程中看到。在这种情况下,不要覆盖parse 方法,而是像你一样使用parse_items。那是因为CrawlSpider 使用parse 将响应转发给回调方法。

        【讨论】:

        • 感谢您的回答。我尝试您的解决方案将定义和回调中的第一个刮板从 parse_item 更改为 parse,但错误消息是相同的。我发现了不同的教程,其中parse 更改为parse_whatever,它们显然有效。例如,mherman.org/blog/2012/11/08/…。我想知道问题是否与回调的 url 的构造和/或类型有关......
        • 更新了答案。使用规则时,您需要不同的蜘蛛类型——基本的scrapy.Spider 将不起作用。
        • 再次感谢。第一个蜘蛛导入 crawlSpider。当然,我是从其他示例中改编而来的。错误消息仍然存在:(
        • 导入是不够的。你必须扩展你的蜘蛛:class bastospider3(CrawlSpider):.
        • GHajba,非常感谢!!!!!!!我不得不更改您所说的内容,并且还必须在规则末尾添加逗号以避免出现错误消息exceptions.TypeError: 'Rule' object is not iterable。规则如下所示:Rule(SgmlLinkExtractor(allow=(), restrict_xpaths=('//div[2]/form[1]/fieldset/a')), callback="parse_item", follow= True),
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-09-15
        • 1970-01-01
        • 1970-01-01
        • 2017-02-23
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多