使用scrapy递归来刮取phpBB论坛

时间:2015-10-08 20:18:57

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

我试图使用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)

我真的很感激这个问题的任何建议(或更好,一个有效的解决方案)。我完全坚持这一点,无论我阅读多少,我都无法找到解决方案:(

3 个答案:

答案 0 :(得分:2)

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

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

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

如果您使用Rule,则需要使用其他蜘蛛。对于那些使用CrawlSpider,您可以在教程中看到。在这种情况下,请勿覆盖parse方法,但请像您一样使用parse_items。这是因为CrawlSpider使用parse将响应转发给回调方法。

答案 1 :(得分:0)

感谢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'变量。

确实,蜘蛛首先返回页面生成'start = 15',然后'start = 30',然后'start = 0',然后再'start = 15',然后'start = 45'... < / p>

我不确定是否必须创建一个新问题,或者未来的读者是否会更好地在此处提出问题。你觉得怎么样?

答案 2 :(得分:0)

因为这已经有5年历史了,所以有很多新的方法。

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

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

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

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