用Scrapy“Spider must return Request”递归刮取钉板

2024-05-16 05:03:10 发布

您现在位置:Python中文网/ 问答频道 /正文

为了磨练我的python和Spark GraphX技能,我一直在尝试构建一个钉板用户和书签的图表。为此,我按以下方式递归地刮取钉板书签:

  1. 从一个用户开始,刮去所有书签
  2. 对于每一个书签(由一个url_slug标识),找到所有保存了相同书签的用户。在
  3. 对于步骤2中的每个用户,重复该过程(转到1,…)

尽管在这里尝试过多个线程的建议(包括使用规则),但当我尝试实现此逻辑时,我得到以下错误:

ERROR: Spider must return Request, BaseItem, dict or None, got 'generator'

我强烈怀疑这与我代码中yield/return的混合有关。在

下面是我的代码的简要说明:

我的mainparse方法查找一个用户的所有书签项(也在带有同一用户书签的任何先前页面之后)并生成parse_bookmark方法来刮取这些书签。在

class PinSpider(scrapy.Spider):
    name = 'pinboard'

    # Before = datetime after 1970-01-01 in seconds, used to separate the bookmark pages of a user
    def __init__(self, user='notiv', before='3000000000', *args, **kwargs):
        super(PinSpider, self).__init__(*args, **kwargs)
        self.start_urls = ['https://pinboard.in/u:%s/before:%s' % (user, before)]
        self.before = before

    def parse(self, response):
        # fetches json representation of bookmarks instead of using css or xpath
        bookmarks = re.findall('bmarks\[\d+\] = (\{.*?\});', response.body.decode('utf-8'), re.DOTALL | re.MULTILINE)

        for b in bookmarks:
            bookmark = json.loads(b)
            yield self.parse_bookmark(bookmark)

        # Get bookmarks in previous pages
        previous_page = response.css('a#top_earlier::attr(href)').extract_first()
        if previous_page:
            previous_page = response.urljoin(previous_page)
            yield scrapy.Request(previous_page, callback=self.parse)

slug{displase这个slug{u,并将其存储在相应的url中,包括

^{pr2}$

最后,parse_url_slug方法找到保存此书签的其他用户,并递归地生成一个scrape.Request来解析他们中的每一个。在

def parse_url_slug(self, response):
    url_slug = UrlSlugItem()

    if response.body:
        soup = BeautifulSoup(response.body, 'html.parser')

        users = soup.find_all("div", class_="bookmark")
        user_list = [re.findall('/u:(.*)/t:', element.a['href'], re.DOTALL) for element in users]
        user_list_flat = sum(user_list, []) # Change from list of lists to list

        url_slug['user_list'] = user_list_flat

        for user in user_list:
            yield scrapy.Request('https://pinboard.in/u:%s/before:%s' % (user, self.before), callback=self.parse)

    return url_slug

(为了以更简洁的方式呈现代码,我删除了存储其他有趣字段或检查重复项的部分。)

任何帮助都将不胜感激!在


Tags: 用户inselfreurlparseresponsepage
1条回答
网友
1楼 · 发布于 2024-05-16 05:03:10

问题是你下面的代码块

yield self.parse_bookmark(bookmark)

因为在你的parse_bookmark中,你有两行以下

^{pr2}$

因为您有yield,所以这个函数的返回值是一个生成器。你把发电机交还给了小淘气,它不知道该怎么处理它。在

修复很简单。将您的代码改为下面

yield from self.parse_bookmark(bookmark)

这将从生成器一次生成一个值,而不是生成器本身。或者你也可以这样做

for ret in self.parse_bookmark(bookmark):
    yield ret

编辑-1

改变你的函数,首先得到物品

yield pin
yield scrapy.Request('https://pinboard.in/url:' + pin['url_slug'], callback=self.parse_url_slug)

还有一个也是

    url_slug['user_list'] = user_list_flat
    yield url_slug
    for user in user_list:
        yield scrapy.Request('https://pinboard.in/u:%s/before:%s' % (user, self.before), callback=self.parse)

稍后屈服将首先安排许多其他请求,当您开始看到被刮伤的项目时需要时间。我运行上面的代码与变化,它刮我很好

2017-08-20 14:02:38 [scrapy.core.scraper] DEBUG: Scraped from <200 https://pinboard.in/u:%5B'semanticdreamer'%5D/before:3000000000>
{'url_slug': 'e1ff3a9fb18873e494ec47d806349d90fec33c66', 'title': 'Flair Conky Offers Dark & Light Version For All Linux Distributions - NoobsLab | Ubuntu/Linux News, Reviews, Tutorials, Apps', 'author': 'semanticdreamer'}
2017-08-20 14:02:38 [scrapy.core.scraper] DEBUG: Scraped from <200 https://pinboard.in/url:d9c16292ec9019fdc8411e02fe4f3d6046185c58>
{'user_list': ['ronert', 'notiv']}

相关问题 更多 >