【问题标题】:Unable to figure out the right way while using a customized method within scrapy在scrapy中使用自定义方法时无法找出正确的方法
【发布时间】:2021-04-03 09:03:39
【问题描述】:

我正在尝试使用 scrapy 与 selenium 结合使用从网站的内页中抓取不同帖子的标题,尽管该网站的内容是静态的。该脚本从登录页面抓取不同帖子的链接,并重用新解析的链接从其内页获取标题。

我知道有一个library 用于在scrapy 中使用硒。但是,我对在这个基本用例中使用该库不感兴趣。

以下蜘蛛中有两种方法。我可以坚持使用一种方法来完成整个工作,但我在这里使用了两种方法来了解如何将链接从一种方法传递到另一种方法,以便在不发出任何请求的情况下在后一种方法中完成其余的事情,如 @ 987654322@.

脚本似乎工作正常。如果我从这里yield self.parse_from_innerpage(response.urljoin(elem)) 踢出yield 并像self.parse_from_innerpage(response.urljoin(elem)) 一样使用,该脚本也可以正常工作。

问题:我应该在 parse 方法中使用 yield 还是不使用当前实现,因为它们都可以互换工作?

我试过了:

import scrapy
from selenium import webdriver
from scrapy.crawler import CrawlerProcess
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC


class StackoverflowSpider(scrapy.Spider):
    name = "stackoverflow"

    start_urls = ['https://stackoverflow.com/questions/tagged/web-scraping']

    def __init__(self):
        self.driver = webdriver.Chrome()
        self.wait = WebDriverWait(self.driver,15)

    def parse(self, response):
        for elem in response.css(".summary .question-hyperlink::attr(href)").getall():
            yield self.parse_from_innerpage(response.urljoin(elem))

    def parse_from_innerpage(self,link):
        self.driver.get(link)
        elem = self.wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, "h1[itemprop='name'] > a")))
        print(elem.text)


if __name__ == "__main__":
    c = CrawlerProcess({
        'USER_AGENT':'Mozilla/5.0',
        'LOG_LEVEL':'ERROR',
    })
    c.crawl(StackoverflowSpider)
    c.start()

【问题讨论】:

  • 您的 parse_from_innerpage 方法不返回任何内容(意味着它返回 None)。这可能会导致生成器返回许多 None 对象。不使用打印,而是返回 elem.text

标签: python python-3.x selenium web-scraping scrapy


【解决方案1】:
def parse_from_innerpage(self,link):
        self.driver.get(link)
        elem = self.wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, "h1[itemprop='name'] > a")))
        print(elem.text)

在尝试回答您的问题之前,我想在parse_from_innerpage(self, link) 函数中添加一点关于您的print() 语句的注释。虽然这个主题是controversially discussed,但最好还是返回有问题的对象 - 您可以稍后决定通过assigning a class instance(然后调用该方法)或直接通过Class.Method(**args)打印它

别挡道 - 让我们来解决您的问题:

我是否应该在 parse 方法中使用 yield 来继续当前的实现,因为它们都可以互换工作?

要回答这个问题 - 或者更确切地说是理解回复 - 我强烈建议查看一些定性资源以掌握 yield 的概念。以下是一些用于进一步阅读目的的链接:

基本上,return 会返回一个指定的值,而另一方面,yield 会产生一个序列 值 - 因此非常适合迭代您获得的值。


让我们看看你的代码:

parse(self, response) method:

def parse(self, response):
        for elem in response.css(".summary .question-hyperlink::attr(href)").getall():
            yield self.parse_from_innerpage(response.urljoin(elem))

简单地说,这个方法需要来自parse_from_innerpage(self, link) 的一些值,因为它“yields”或遍历接收列表。 但是,您的parse_from_innerpage(self,link) 没有返回任何内容 - 看看,有没有 return 声明!:

def parse_from_innerpage(self,link):
        self.driver.get(link)
        elem = self.wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, "h1[itemprop='name'] > a")))
        
        #Use return instead of print()
        print(elem.text)

由于parse_from_innerpage(**args) 返回None,parse(**args) 也不会返回任何内容,因为没有什么可以迭代/返回。因此,您应该将print() 替换为return。


我建议查看Scrapy Documentation(尤其是Scrapy at a glance)以了解Scrapy 的具体工作原理以及它期望scrapy.Spider 做什么以实现您的目标。基本上,parse(**args) 方法用作生成器(参考already mentioned StackOverflow question)以获得您想要获得的结果 - 一旦没有元素可以迭代(它停止)它“向您显示它们”:

在解析回调中,我们使用 CSS 循环引用元素 选择器,使用提取的引号文本生成 Python dict 和 作者,寻找下一页的链接并安排另一个请求 使用与回调相同的解析方法

...但正如您提到的那样,parse(**args) 不幸地收到了None,原因是print() 而不是return。

【讨论】:

    【解决方案2】:

    yield 在 python 中用于从生成器内部“放弃”运行并返回一个值。

    所以这里parse 方法返回parse_from_innerpage 的结果。但是parse_from_innerpage 没有return 语句,这意味着它返回None。

    阅读 scrapy 文档中的 this,了解 scrapy 期望蜘蛛做什么。

    简而言之,scrapy 使用parse 方法作为结果生成器,然后在它停止运行时将它们显示给您(用完可以抓取的链接)。 将print 替换为returns,一切都应该按预期工作

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-06-26
      • 1970-01-01
      • 1970-01-01
      • 2021-04-08
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多