python爬虫框架scrapy实例详解
生成项目
scrapy提供一个东西来生成项目,生成的项目中预置了一些文件,用户需要在这些文件中添加本身的代码。
打开呼吁行,执行:scrapy startproject tutorial,生成的项目雷同下面的布局
tutorial/
scrapy.cfg
tutorial/
__init__.py
items.py
pipelines.py
settings.py
spiders/
__init__.py
…
scrapy.cfg是项目标设置文件
用户本身写的spider要放在spiders目次下面,一个spider雷同
from scrapy.spider import BaseSpider class DmozSpider(BaseSpider): name = "dmoz" allowed_domains = ["dmoz.org"] start_urls = [ "http://www.dmoz.org/Computers/Programming/Languages/Python/Books/", "http://www.dmoz.org/Computers/Programming/Languages/Python/Resources/" ] def parse(self, response): filename = response.url.split("/")[-2] open(filename, 'wb').write(response.body)
name属性很重要,差异spider不能利用沟通的name
start_urls是spider抓取网页的起始点,可以包罗多个url
parse要领是spider抓到一个网页今后默认挪用的callback,制止利用这个名字来界说本身的要领。
当spider拿到url的内容今后,会挪用parse要领,而且通报一个response参数给它,response包括了抓到的网页的内容,在parse要领里,你可以从抓到的网页内里理会数据。上面的代码只是简朴地把网页内容生存到文件。
开始抓取
你可以打开呼吁行,进入生成的项目根目次tutorial/,执行 scrapy crawl dmoz, dmoz是spider的name。
理会网页内容
scrapy提供了利便的步伐从网页中理会数据,这需要利用到HtmlXPathSelector
from scrapy.spider import BaseSpider from scrapy.selector import HtmlXPathSelector class DmozSpider(BaseSpider): name = "dmoz" allowed_domains = ["dmoz.org"] start_urls = [ "http://www.dmoz.org/Computers/Programming/Languages/Python/Books/", "http://www.dmoz.org/Computers/Programming/Languages/Python/Resources/" ] def parse(self, response): hxs = HtmlXPathSelector(response) sites = hxs.select('//ul/li') for site in sites: title = site.select('a/text()').extract() link = site.select('a/@href').extract() desc = site.select('text()').extract() print title, link, desc
HtmlXPathSelector利用了Xpath来理会数据
//ul/li暗示选择所有的ul标签下的li标签
a/@href暗示选择所有a标签的href属性
a/text()暗示选择a标签文本
a[@href="abc"]暗示选择所有href属性是abc的a标签
我们可以把理会出来的数据生存在一个scrapy可以利用的工具中,然后scrapy可以辅佐我们把这些工具生存起来,而不消我们本身把这些数据存到文件中。我们需要在items.py中添加一些类,这些类用来描写我们要生存的数据
from scrapy.item import Item, Field
class DmozItem(Item):
title = Field()
link = Field()
desc = Field()
然后在spider的parse要领中,我们把理会出来的数据生存在DomzItem工具中。
from scrapy.spider import BaseSpider from scrapy.selector import HtmlXPathSelector from tutorial.items import DmozItem class DmozSpider(BaseSpider): name = "dmoz" allowed_domains = ["dmoz.org"] start_urls = [ "http://www.dmoz.org/Computers/Programming/Languages/Python/Books/", "http://www.dmoz.org/Computers/Programming/Languages/Python/Resources/" ] def parse(self, response): hxs = HtmlXPathSelector(response) sites = hxs.select('//ul/li') items = [] for site in sites: item = DmozItem() item['title'] = site.select('a/text()').extract() item['link'] = site.select('a/@href').extract() item['desc'] = site.select('text()').extract() items.append(item) return items
在呼吁行执行scrapy的时候,我们可以加两个参数,让scrapy把parse要领返回的items输出到json文件中
scrapy crawl dmoz -o items.json -t json
items.json会被放在项目标根目次
让scrapy自动抓取网页上的所有链接
上面的示例中scrapy只抓取了start_urls内里的两个url的内容,可是凡是我们想实现的是scrapy自动发明一个网页上的所有链接,然后再去抓取这些链接的内容。为了实现这一点我们可以在parse要领内里提取我们需要的链接,然后结构一些Request工具,而且把他们返回,scrapy会自动的去抓取这些链接。代码雷同:
class MySpider(BaseSpider): name = 'myspider' start_urls = ( 'http://example.com/page1', 'http://example.com/page2', ) def parse(self, response): # collect `item_urls` for item_url in item_urls: yield Request(url=item_url, callback=self.parse_item) def parse_item(self, response): item = MyItem() # populate `item` fields yield Request(url=item_details_url, meta={'item': item}, callback=self.parse_details) def parse_details(self, response): item = response.meta['item'] # populate more `item` fields return item
#p#分页标题#e#
parse是默认的callback, 它返回了一个Request列表,scrapy自动的按照这个列表抓取网页,每当抓到一个网页,就会挪用parse_item,parse_item也会返回一个列表,scrapy又会按照这个列表去抓网页,而且抓到后挪用parse_details
为了让这样的事情更容易,scrapy提供了另一个spider基类,操作它我们可以利便的实现自动抓取链接. 我们要用到CrawlSpider
from scrapy.contrib.linkextractors.sgml import SgmlLinkExtractor class MininovaSpider(CrawlSpider): name = 'mininova.org' allowed_domains = ['mininova.org'] start_urls = ['http://www.mininova.org/today'] rules = [Rule(SgmlLinkExtractor(allow=['/tor/\d+'])), Rule(SgmlLinkExtractor(allow=['/abc/\d+']), 'parse_torrent')] def parse_torrent(self, response): x = HtmlXPathSelector(response) torrent = TorrentItem() torrent['url'] = response.url torrent['name'] = x.select("//p/text()").extract() torrent['description'] = x.select("//div[@id='description']").extract() torrent['size'] = x.select("//div[@id='info-left']/p[2]/text()[2]").extract() return torrent
对比BaseSpider,新的类多了一个rules属性,这个属性是一个列表,它可以包括多个Rule,每个Rule描写了哪些链接需要抓取,哪些不需要。这是Rule类的文档http://doc.scrapy.org/en/latest/topics/spiders.html#scrapy.contrib.spiders.Rule
这些rule可以有callback,也可以没有,当没有callback的时候,scrapy简朴的follow所有这些链接.
pipelines.py的利用
在pipelines.py中我们可以添加一些类来过滤掉我们不想要的item,把item生存到数据库。
from scrapy.exceptions import DropItem class FilterWordsPipeline(object): """A pipeline for filtering out items which contain certain words in their description""" # put all words in lowercase words_to_filter = ['politics', 'religion'] def process_item(self, item, spider): for word in self.words_to_filter: if word in unicode(item['description']).lower(): raise DropItem("Contains forbidden word: %s" % word) else: return item
假如item不切合要求,那么就抛一个异常,这个item不会被输出到json文件中。
要利用pipelines,我们还需要修改settings.py
添加一行
ITEM_PIPELINES = ['dirbot.pipelines.FilterWordsPipeline']
此刻执行scrapy crawl dmoz -o items.json -t json,不切合要求的item就被过滤掉了