如何使用 Python Scrapy 抓取单个页面的多个部分?
How to scrape multile parts of a single page with Python Scrapy?
假设我有一个 HTML 文件,其中包含多个具有不同结构的部分,需要截然不同的抓取。 蜘蛛布局的最佳做法是什么?
我应该使用一个蜘蛛还是多个蜘蛛?我是否应该多次请求相同的 URL,每次使用不同的回调函数?或者只是按顺序解析不同的部分?我问的是能够与框架的其他部分一起玩——比如 items 和 pipleines——以及性能、限制和缓存方面.
那么,有什么最佳实践建议吗?社区中使用的规则或惯例?
多个请求
如果我多次请求 URL 它是否被缓存/限制?或者对引擎的每个请求都会导致对 "external web server"?
的请求
class MultiSpider(scrapy.Spider):
"""Parse the parts in parallel."""
name = 'multispider'
def start_requests(self):
url = 'https://en.wikipedia.org/wiki/Main_Page'
yield scrapy.Request(url=url, callback=self.parser_01)
yield scrapy.Request(url=url, callback=self.parser_02)
def parser_01(self, response):
selector = response.xpath('//some/path')
if selector is not None:
# do stuff with *selector* and
yield {}
def parser_0(self, response):
selector = response.xpath('//some/other/path')
if selector is not None:
# do very different stuff with *selector* and
yield {}
多个解析器函数
如果我想避免庞大的 parse
函数,而是针对不同的任务/部分使用多个函数,是否有特别好的/坏的方法来构建它(例如 "how to yield from where")?
class SeqSpider(scrapy.Spider):
"""Parse the page sequentially."""
name = 'seqspider'
start_urls = ['https://en.wikipedia.org/wiki/Main_Page', ]
def parse(self, response):
selector = response.xpath('//some/path')
if selector:
yield from self.parser_01(response, selector):
selector = response.xpath('//some/other/path')
if selector:
yield from self.parser_02(response, selector):
def parser_01(self, response, selector):
# do stuff with *selector* and
yield {}
def parser_0(self, response, selector):
# do very different stuff with *selector* and
yield {}
如果是单个页面,我建议使用一个蜘蛛。一次请求页面并解析您需要的所有数据(您可以为此使用一个或多个函数)。
我也推荐使用物品,例如
import scrapy
class AmazonItem(scrapy.Item):
product_name = scrapy.Field()
product_asin = scrapy.Field()
product_avg_stars = scrapy.Field()
product_num_reviews = scrapy.Field()
pass
如果您想将抓取的数据保存到数据库中,您应该使用管道。
为了回答您关于如何构造蜘蛛/最佳实践的问题,我通常会这样做:
避免构建在同一页面上工作的多个蜘蛛 - 因为目标网站的带宽通常是瓶颈,并且在网站上创建不必要的流量不被视为有礼貌的抓取。
对同一个 URL 创建多个请求也是如此:它可能会给目标网站带来不必要的流量,这不是很好的抓取行为。默认情况下,scrapy 还会过滤重复的请求,因此您可能突然想知道为什么不是所有请求都被执行。
(注意:有很多方法可以解决这个问题,也可以使用代理等......但这会使事情不必要地复杂化)
因此,如果您想避免做很多不同事情的大型解析方法,请随意将其拆分。与您在自己的示例中建议的非常相似。我什至会更进一步,将完整的处理步骤封装到单独的解析方法中,例如
class SomeSpider(scrapy.Spider):
def parse(self, response):
yield self.parse_widgets_type_a(response)
yield self.parse_widgets_type_b(response)
# ....
yield self.follow_interesting_links(response)
def parse_widgets_type_a(self, response):
# ....
def parse_widgets_type_b(self, response):
# ....
def follow_interesting_links(self, response):
# ....
yield Request(interesting_url)
基于此模板,您甚至可能希望将不同的解析方法重构为不同的 Mixin 类。
假设我有一个 HTML 文件,其中包含多个具有不同结构的部分,需要截然不同的抓取。 蜘蛛布局的最佳做法是什么?
我应该使用一个蜘蛛还是多个蜘蛛?我是否应该多次请求相同的 URL,每次使用不同的回调函数?或者只是按顺序解析不同的部分?我问的是能够与框架的其他部分一起玩——比如 items 和 pipleines——以及性能、限制和缓存方面.
那么,有什么最佳实践建议吗?社区中使用的规则或惯例?
多个请求
如果我多次请求 URL 它是否被缓存/限制?或者对引擎的每个请求都会导致对 "external web server"?
的请求class MultiSpider(scrapy.Spider):
"""Parse the parts in parallel."""
name = 'multispider'
def start_requests(self):
url = 'https://en.wikipedia.org/wiki/Main_Page'
yield scrapy.Request(url=url, callback=self.parser_01)
yield scrapy.Request(url=url, callback=self.parser_02)
def parser_01(self, response):
selector = response.xpath('//some/path')
if selector is not None:
# do stuff with *selector* and
yield {}
def parser_0(self, response):
selector = response.xpath('//some/other/path')
if selector is not None:
# do very different stuff with *selector* and
yield {}
多个解析器函数
如果我想避免庞大的 parse
函数,而是针对不同的任务/部分使用多个函数,是否有特别好的/坏的方法来构建它(例如 "how to yield from where")?
class SeqSpider(scrapy.Spider):
"""Parse the page sequentially."""
name = 'seqspider'
start_urls = ['https://en.wikipedia.org/wiki/Main_Page', ]
def parse(self, response):
selector = response.xpath('//some/path')
if selector:
yield from self.parser_01(response, selector):
selector = response.xpath('//some/other/path')
if selector:
yield from self.parser_02(response, selector):
def parser_01(self, response, selector):
# do stuff with *selector* and
yield {}
def parser_0(self, response, selector):
# do very different stuff with *selector* and
yield {}
如果是单个页面,我建议使用一个蜘蛛。一次请求页面并解析您需要的所有数据(您可以为此使用一个或多个函数)。
我也推荐使用物品,例如
import scrapy
class AmazonItem(scrapy.Item):
product_name = scrapy.Field()
product_asin = scrapy.Field()
product_avg_stars = scrapy.Field()
product_num_reviews = scrapy.Field()
pass
如果您想将抓取的数据保存到数据库中,您应该使用管道。
为了回答您关于如何构造蜘蛛/最佳实践的问题,我通常会这样做:
避免构建在同一页面上工作的多个蜘蛛 - 因为目标网站的带宽通常是瓶颈,并且在网站上创建不必要的流量不被视为有礼貌的抓取。
对同一个 URL 创建多个请求也是如此:它可能会给目标网站带来不必要的流量,这不是很好的抓取行为。默认情况下,scrapy 还会过滤重复的请求,因此您可能突然想知道为什么不是所有请求都被执行。
(注意:有很多方法可以解决这个问题,也可以使用代理等......但这会使事情不必要地复杂化)
因此,如果您想避免做很多不同事情的大型解析方法,请随意将其拆分。与您在自己的示例中建议的非常相似。我什至会更进一步,将完整的处理步骤封装到单独的解析方法中,例如
class SomeSpider(scrapy.Spider): def parse(self, response): yield self.parse_widgets_type_a(response) yield self.parse_widgets_type_b(response) # .... yield self.follow_interesting_links(response) def parse_widgets_type_a(self, response): # .... def parse_widgets_type_b(self, response): # .... def follow_interesting_links(self, response): # .... yield Request(interesting_url)
基于此模板,您甚至可能希望将不同的解析方法重构为不同的 Mixin 类。