zl程序教程

您现在的位置是:首页 >  其他

当前栏目

scrapy用不同规则抓取多个网站(基于csv文件)以及向爬虫传递参数(参数可默认)

2023-04-18 14:52:10 时间

大多数情况下每个网站对应一个爬虫,但是也有很多时候需要一个爬虫抓取多个网站,而它们之间的唯一区别只是XPath表达式不同。在这种情况下,对应每个网站编写一个爬虫有些大材小用,只需一个爬虫即可解决。

首先创建一个.csv文件 ,按照下图填写一些url和XPath表达式,保存为todo.csv并放到工程的目录(也就是scrapy.cfg文件所在的目录)。

scrapy用不同规则抓取多个网站(基于csv文件)以及向爬虫传递参数(参数可默认)

Python有一个内建的库专门处理.csv文件,需引入import csv。用下面的代码:

$ pwd /root/book/ch05/generic2 $ python >>> import csv >>> with open("todo.csv", "rU") as f: reader = csv.DictReader(f) for line in reader: print line

csv文件的第一行会被自动当做表头,其中的内容作为将要生成的字典的键。每次for循环中,文件的每一行都生成一个字典。运行上面的代码可以得到以下输出:

{'url': ' http://a.html', 'price': '//*[@id="prcIsum"]/text()', 'name': '//*[@id="itemTitle"]/text()'} {'url': ' http://b.html', 'price': '//span/strong/text()', 'name': '//h1/text()'} {'url': ' http://c.html', 'price': '', 'name': '//* [@id="product-desc"]/span/text()'}

由于不是抓取预先知道的url,而是从文件中读取url,这就需要重新实现start_request()函数。对于文件的每一行,产生一个Request并yield。然后在request.meta中保存XPath表达式以便在parse()函数中使用。最后使用Item和一个ItemLoader来填充Item的字段。

import csv import scrapy

from scrapy.http import Request from scrapy.loader import ItemLoader from scrapy.item import Item, Field class FromcsvSpider(scrapy.Spider): name = "fromcsv"

def start_requests(self): with open("todo.csv", "rU") as f: reader = csv.DictReader(f) for line in reader: request = Request(line.pop('url')) request.meta['fields'] = line yield request

def parse(self, response): item = Item() l = ItemLoader(item=item, response=response) for name, xpath in response.meta['fields'].iteritems(): if xpath: item.fields[name] = Field() l.add_xpath(name, xpath) return l.load_item()

上面的代码可以会跟平常的代码有一些不同:

  • 没有为整个工程生成Item

    item = Item() l = ItemLoader(item=item, response=response)

  • 用Item的成员变量fields来动态地添加字段
    item.fields[name] = Field()
    l.add_xpath(name, xpath)

  • 硬编码todo.csv文件在实践中不太好。Scrapy可以在命令行中用-a来向爬虫传递参数。例如,-a variable=value,这样会设置爬虫的一个variable属性,可以在程序中用self.variable来访问。如果没有提供的话还可以使用默认参数:getattr(self, 'variable', 'default')。综上,可以把原来的打开文件的代码换成:

    with open(getattr(self, "file", "todo.csv"), "rU") as f:

    现在todo.csv是默认值,除非用-a选项显式地设置url源文件。如果存在另一个文件another_todo.csv,可以运行下面的命令:

    $ scrapy crawl fromcsv -a file=another_todo.csv -o out.csv