1. 什么是Scrapy框架?
Scrapy是一个基于Python语言的web抓取框架,可以方便地抓取Web站点,并将抓取的数据存储到本地或各种数据库中。它使用了异步IO模型,处理速度快、效率高,并且支持多个网站的抓取任务。
1.1 安装Scrapy框架
要使用Scrapy框架,需要先安装Scrapy模块。可以通过命令行输入以下命令安装:
pip install scrapy
详细的安装过程可以查看官方文档。安装完成后,可以通过以下命令查看版本信息:
scrapy version
2. Scrapy框架的基本结构
Scrapy框架的三个主要组成部分是:
Spider:定义如何抓取Web站点的规则,以及如何从网页中提取数据
Item:定义抓取的数据模型
Pipeline:定义数据的处理过程,例如存储到数据库或输出到文件等
2.1 Spider组件
Spider组件是Scrapy框架中最重要的组件之一,它定义了如何抓取Web站点的规则,并且从网页中提取数据。Spider组件需要继承自Scrapy提供的Spider类,并实现几个方法:
import scrapy
class MySpider(scrapy.Spider):
name = 'myspider'
allowed_domains = ['example.com']
start_urls = ['https://example.com']
def parse(self, response):
# 解析网页,抓取所需数据
pass
上面的代码就定义了一个简单的Spider。其中,name
属性指定了Spider的名称,allowed_domains
属性指定了允许抓取的域名,start_urls
属性定义了起始网页的URL地址。
Spider组件的核心方法是parse()
方法,它接受一个response对象作为参数,这个对象包含了网页的HTML代码。Spider组件需要解析HTML代码,抓取到其中所需的数据。
2.2 Item组件
Item组件指定了抓取的数据模型,它可以看作是抓取到数据的一个容器。每个Item对象代表一条记录,包含了多个字段。
import scrapy
class MyItem(scrapy.Item):
field1 = scrapy.Field()
field2 = scrapy.Field()
field3 = scrapy.Field()
上面的代码就定义了一个简单的Item组件。其中,Field
类定义了一个字段。Item组件的每个字段都可以设置为一个Field
对象。这样,Spider组件抓取到的数据就可以保存到Item中。
2.3 Pipeline组件
Pipeline组件定义了数据的处理过程,例如存储到数据库或输出到文件等。Pipeline组件需要继承自Scrapy提供的Pipeline类,并实现几个方法:
class MyPipeline(object):
def process_item(self, item, spider):
# 处理数据
pass
上面的代码就定义了一个简单的Pipeline。其中,process_item()
方法接受一个Item对象和Spider对象作为参数,Pipeline组件需要对Item对象进行处理。一般情况下,处理完成后的数据会被输出到文件或数据库中。
3. Scrapy框架的使用方法
在实际使用Scrapy框架时,一般按以下步骤进行:
定义Spider组件,写好抓取规则,抓取需要的数据
定义Item组件,设置好数据模型
定义Pipeline组件,处理抓取到的数据,例如存储到数据库或文件中
运行Scrapy命令,启动抓取流程
3.1 定义Spider组件
定义Spider组件最关键的是抓取规则,Scrapy提供了强大的选择器和XPath等语法,可以方便地从HTML代码中提取所需的数据。例如,以下代码就用XPath语法从网页中提取了所有标签的链接地址:
import scrapy
class MySpider(scrapy.Spider):
name = 'myspider'
allowed_domains = ['example.com']
start_urls = ['https://example.com']
def parse(self, response):
# 提取所有链接地址
for href in response.xpath('//a/@href'):
url = response.urljoin(href.extract())
yield scrapy.Request(url, callback=self.parse_item)
def parse_item(self, response):
# 解析详情页,提取所需数据
pass
以上代码中,response.xpath()
方法返回了一个XPath选择器对象,代表了网页中所有的标签元素。这个选择器对象使用了XPath语法,选取了所有标签的href
属性。然后,通过response.urljoin()
方法,将这个链接地址补全,变为绝对地址。
抓取到所有链接地址后,使用scrapy.Request()
方法重新请求这个URL地址,并返回一个新的response对象。这个response对象又会被送到parse_item()
方法中,提取网页中所需的数据。
3.2 定义Item组件
Item组件定义了抓取得到的数据模型,例如在上面的例子中,可以定义如下的Item:
import scrapy
class MyItem(scrapy.Item):
title = scrapy.Field()
content = scrapy.Field()
datetime = scrapy.Field()
author = scrapy.Field()
这样,Spider组件就可以从网页中抓取这些数据,并且存放到Item对象中。
3.3 定义Pipeline组件
Pipeline组件定义了数据的处理过程,例如存储到数据库或输出到文件等。例如,以下代码将抓取到的数据保存到了MongoDB数据库中:
import pymongo
class MyPipeline(object):
def __init__(self, mongo_uri, mongo_db):
self.mongo_uri = mongo_uri
self.mongo_db = mongo_db
def open_spider(self, spider):
self.client = pymongo.MongoClient(self.mongo_uri)
self.db = self.client[self.mongo_db]
def close_spider(self, spider):
self.client.close()
def process_item(self, item, spider):
collection = self.db[type(item).__name__.lower()]
collection.insert_one(dict(item))
return item
以上代码中,open_spider()
方法在Spider启动时被调用,连接到MongoDB数据库。然后,process_item()
方法接收一个Item对象,将其插入到MongoDB的对应集合中。最后,close_spider()
方法在Spider关闭时被调用,关闭MongoDB数据库连接。
3.4 运行Scrapy命令
定义好Spider组件、Item组件和Pipeline组件后,就可以使用Scrapy命令来运行了:
scrapy crawl myspider -o result.json
其中,myspider
是Spider的名称,-o
参数指定输出的文件名,这里将抓取结果保存为了JSON格式的文件。
4. Scrapy框架的示例
下面以一个具体的应用为例,介绍Scrapy框架的实际使用方法。
4.1 应用背景
现在,有一个网站https://www.jianshu.com/,想要抓取其中所发布的所有文章的标题和内容,保存到本地。
4.2 编写Spider组件
首先,定义Spider组件myjianshu:
import scrapy
class MyJianshuSpider(scrapy.Spider):
name = 'myjianshu'
allowed_domains = ['www.jianshu.com']
start_urls = ['https://www.jianshu.com/']
def parse(self, response):
# 提取所有文章链接地址
for href in response.xpath('//a[@class="title"]/@href'):
url = response.urljoin(href.extract())
yield scrapy.Request(url, callback=self.parse_item)
def parse_item(self, response):
# 解析详情页,提取文章标题和内容
title = response.xpath('//h1/text()').extract_first()
content = ''.join(response.xpath('//article[@class="article"]/p/text()')
.extract()).strip()
yield {'title': title, 'content': content}
该Spider组件的作用是从www.jianshu.com中抓取所有文章的标题和内容。其中,parse()
方法用于从网站中提取所有文章的链接地址,使用scrapy.Request()
方法重新请求这些链接地址,然后返回到parse_item()
方法中解析数据。
在parse_item()
方法中,使用XPath选择器找到了文章标题和内容。这些数据将被存储到一个字典中,并且使用yield
关键字返回。
4.3 编写Item组件
上面提到了,需要抓取的数据包括文章的标题和内容。可以使用Item组件来设置数据模型:
import scrapy
class JianshuItem(scrapy.Item):
title = scrapy.Field()
content = scrapy.Field()
这里只定义了两个字段,分别代表文章的标题和内容。这些数据会被保存到Item对象中。
4.4 编写Pipeline组件
要将抓取到的数据保存到本地,可以使用Pipeline组件,将数据以JSON格式保存到文件中。代码如下:
import json
class JianshuPipeline(object):
def __init__(self):
self.file = open('result.json', 'w')
def process_item(self, item, spider):
line = json.dumps(dict(item)) + "\n"
self.file.write(line)
return item
def spider_closed(self, spider):
self.file.close()
在__init__()
方法中打开了一个文件,并且在process_item()
方法中将抓取到的数据以JSON格式保存到文件中。在spider_closed()
方法中关闭了文件。
4.5 运行Scrapy命令
在完成Spider组件、Item组件和Pipeline组件的编写后,可以使用以下命令运行:
scrapy crawl myjianshu
这样,Scrapy框架将从www.jianshu.com中抓取所有文章的标题和内容,并保存到result.json文件中。
5. 总结
本文介绍了Scrapy框架的基本原理和使用方法。通过实例,演示了如何编写Spider组件、Item组件和Pipeline组件,并使用Scrapy命令来运行。Scrapy框架具有高效、高速、易用的特点,在Web抓取的应用中具有广泛的应用。