1

我正在尝试用scrapy制作一个专门针对的网络爬虫,它会返回我的结果对象。我被卡住了,可能正在完全倒退。

更具体地说,对于TheScienceForum.com上的每个子论坛(数学、物理等),我想获取每个子论坛中所有主题的标题,并最终得到一个具有论坛名称的对象和论坛中所有主题的标题列表。

最终目标是对主题标题进行文本分析,以确定与每个论坛相关的最常见术语/行话。最终我也想对线程本身进行分析。

我有一个类 Item 定义如下:

from scrapy.item import Item, Field

class ProjectItem(Item):
    name = Field() #the forum name
    titles = Field() #the titles

我可能会误解项目的工作原理,但我希望每个子论坛都有一个项目,该子论坛的所有主题标题都在同一项目的列表中。

我写的爬虫看起来像这样,但没有按预期运行:

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

    from individualProject.items import ProjectItem

    class TheScienceForum(CrawlSpider):
        name = "TheScienceForum.com"
        allowed_domains = ["theScienceForum.com"]
        start_urls = ["http://www.thescienceforum.com"]
        rules = [Rule(SgmlLinkExtractor(restrict_xpaths=['//h2[@class="forumtitle"]/a']), 'parse_one'),Rule(SgmlLinkExtractor(restrict_xpaths=['//div[@class="threadpagenav"]']), 'parse_two')]

        def parse_one(self, response):
            Sel = HtmlXPathSelector(response)
            forumNames = Sel.select('//h2[@class="forumtitle"]/a/text()').extract()

            items = []
        for forumName in forumNames:
            item = projectItem()
            item['name'] = forumName
            items.append(item)
        yield items

        def parse_two(self, response):
            Sel = HtmlXPathSelector(response)
            threadNames = Sel.select('////h3[@class="threadtitle"]/a/text()').extract()
            for item in items:
                for title in titles:
                    if Sel.select('//h1/span[@class="forumtitle"]/text()').extract()==item.name:
                        item['titles'] += Sel.select('//h3[@class="threadtitle"]/a/text()').extract()
            return items

这个想法是从所有子论坛名称所在的站点的主页开始。第一条规则只允许链接到第一个子论坛页面和与之关联的解析函数,它意味着为每个子论坛创建一个项目,在论坛名称中为“名称”属性添加子项。

对于以下请求,使用第二条规则,蜘蛛仅限于导航包含子论坛的所有线程(分页链接)的页面。第二个解析方法旨在将线程标题添加到与当前子论坛名称对应的项目(在第一个解析方法中创建)(Sel.select('//h1/span[@class="forumtitle"]/ text()').extract())

蜘蛛正在爬到所有主要的论坛页面,但是对于每个页面,我都会收到以下错误:

2013-11-01 13:05:37-0400 [TheScienceForum.com] ERROR: Spider must return Request, BaseItem or None, got 'list' in <GET http://www.thescienceforum.com/mathematics/>

任何帮助或建议将不胜感激。谢谢!

4

2 回答 2

2

我找到了解决我遇到的爬行问题的方法。以下代码在论坛主页上启动蜘蛛,为每个子论坛创建一个新项目。蜘蛛然后跟随链接,进入子论坛的每个页面,沿途收集线程标题(将它们添加到相关项目,所有这些都与下一个请求一起传递)。代码如下:

from scrapy.spider import BaseSpider
from scrapy.selector import HtmlXPathSelector
from scrapy.contrib.linkextractors.sgml import SgmlLinkExtractor
from scrapy.http import Request

from individualProject.items import ProjectItem

class TheScienceForum(BaseSpider):
    name = "TheScienceForum.com"
    allowed_domains = ["www.thescienceforum.com"]
    start_urls = ["http://www.thescienceforum.com"]
    #rules = [Rule(SgmlLinkExtractor(restrict_xpaths=['//h2[@class="forumtitle"]/a']), 'parse_one'),Rule(SgmlLinkExtractor(restrict_xpaths=['//div[@class="threadpagenav"]']), 'parse_two')]

    def parse(self, response):
        Sel = HtmlXPathSelector(response)
        forumNames = Sel.select('//h2[@class="forumtitle"]/a/text()').extract()
        items = []
        for forumName in forumNames:
            item = ProjectItem()
            item['name'] = forumName
            items.append(item)


        forums = Sel.select('//h2[@class="forumtitle"]/a/@href').extract()
        itemDict = {}
        itemDict['items'] = items
        for forum in forums:
            yield Request(url=forum,meta=itemDict,callback=self.addThreadNames)


    def addThreadNames(self, response):
        items = response.meta['items']
        Sel = HtmlXPathSelector(response)
        currentForum = Sel.select('//h1/span[@class="forumtitle"]/text()').extract()
        for item in items:
            if currentForum==item['name']:
                item['thread'] += Sel.select('//h3[@class="threadtitle"]/a/text()').extract()
        self.log(items)


        itemDict = {}
        itemDict['items'] = items
        threadPageNavs = Sel.select('//span[@class="prev_next"]/a[@rel="next"]/@href').extract()
        for threadPageNav in threadPageNavs:  
            yield Request(url=threadPageNav,meta=itemDict,callback=self.addThreadNames)

我现在遇到的问题是如何保存要分类的数据(稍后进行分析)。我在这方面提出了另一个问题。

于 2013-11-01T22:45:23.810 回答
0

正如Christian Temus所建议的那样,在您面临的问题上更具描述性。查看代码我可以提出一些建议

  1. 您应该在 for 循环中执行“yield item”,而不是返回项目列表。

  2. 使用爬虫

  3. 如果您使用 crawlspider 将“parse”方法重命名为其他名称,例如 parse_titles。

于 2013-11-01T06:47:06.563 回答