scrapy分页抓取网页(()生成项目scrapy提供一个工具来生成的项目)
优采云 发布时间: 2021-11-23 00:09scrapy分页抓取网页(()生成项目scrapy提供一个工具来生成的项目)
构建项目
Scrapy 提供了一个生成项目的工具。生成的项目中预设了一些文件,用户需要在这些文件中添加自己的代码。
打开命令行执行:scrapy startproject教程,生成的项目类似如下结构
教程/
配置文件
教程/
__init__.py
项目.py
管道.py
设置.py
蜘蛛/
__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属性很重要,不同的蜘蛛不能使用相同的名字
start_urls是蜘蛛爬取网页的起点,可以收录多个url
parse 方法是蜘蛛抓取网页后默认调用的回调。避免使用此名称来定义您自己的方法。
当spider获取到url的内容时,它会调用parse方法并传递一个响应参数给它。响应收录捕获的网页的内容。在 parse 方法中,您可以解析捕获的网页中的数据。上面的代码只是将网页的内容保存到一个文件中。
开始爬行
可以打开命令行,进入生成的项目根目录tutorial/,执行scrapy crawl dmoz,其中dmoz是蜘蛛的名字。
解析网页内容
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[@href="abc"] 表示选择所有href属性为abc的a标签
我们可以将解析后的数据保存在一个scrapy可以使用的对象中,然后scrapy可以帮助我们保存这些对象,而不是自己将数据存储在一个文件中。我们需要在items.py中添加一些类,这些类是用来描述我们要保存的数据的
从scrapy.item导入项目,字段
类 DmozItem(Item):
标题 = 字段()
链接 = 字段()
描述 = 字段()
然后在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文件中
抓取 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
parse 是默认回调。它返回一个请求列表。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("//h1/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 相比,新类多了一个规则属性。该属性是一个列表,可以收录多个规则。每个规则都描述了哪些链接需要被抓取,哪些不需要。这是规则类#scrapy.contrib.spiders.Rule 的文档
这些规则可以有回调或没有回调。当没有回调时,scrapy 只是跟随所有这些链接。
使用pipelines.py
在 pipelines.py 中,我们可以添加一些类来过滤掉我们不想要的项目并将这些项目保存到数据库中。
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文件中。
要使用管道,我们还需要修改 settings.py
添加一行
ITEM_PIPELINES = ['dirbot.pipelines.FilterWordsPipeline']
现在执行scrapy crawl dmoz -o items.json -t json,过滤掉不符合要求的item