Scrapy 是用纯 Python 实现一个为了爬取网站数据、提取结构性数据而编写的应用框架,用户只需要定制开发几个模块就可以实现一个网络爬虫程序,其采用了异步通讯的方式可以快速进行数据爬取。在python爬取豆瓣电影Top250我们实现了使用requests模块爬取电影信息,今天使用scrapy框架实现这一需求,体验一下scrapy框架的简洁性和快速性。
如果还没有安装scrapy框架,可以浏览一下python安装scrapy实现安装。
1.新建项目
在开始爬取之前,必须创建一个新的 Scrapy 项目。进入自定义的目录中,运行下列命令:
scrapy startproject douban
project 名称可以自定义,但是不能以数字开头。
然后会生成一个douban文件夹,我们进入到这个文件夹,运行下面的命令生成一个爬虫:
cd douban
scrapy genspider doubanspider douban.com
注:爬虫名不能和项目名相同。
然后我们通过pycharm打开这个项目,了解一下这个框架:
- scrapy.cfg:项目的配置文件
- douban/:项目的 Python 模块,将会从这里引用代码
- douban/items.py:项目的目标文件,一般不用更改
- douban/pipelines.py:项目的管道文件,一般在数据输出、保存、分析时使用
- douban/settings.py:项目的设置文件,根据需要进行设置
- douban/spiders/:存储爬虫代码目录,完成数据请求和解析
2.爬取和保存数据
爬取和解析数据
通过在douban/spiders/doubanspider.py编写代码实现,这个文件下初始只定义了一个类,类名为我们生成的爬虫名+Spider,下面的name
就是我们生成的爬虫名,allowed_domains
是允许爬取的域名,start_urls
是最开始爬取的网站,它的响应结果会固定返回给parse函数进行解析。有一点要明确的是这个系统自动生成的parse函数是不可以改名的,当然我们可以定义其他的函数。
import scrapy
import re
class DoubanspiderSpider(scrapy.Spider):
name = 'doubanspider' # 爬虫名称
allowed_domains = ['douban.com'] # 允许爬取的域名
start_urls = ['https://movie.douban.com/top250'] # 最开始爬取的网站
def parse(self, response):
item = {}
re_path = '(\d*)'
li_list = response.xpath('//*[@id="content"]/div/div[1]/ol/li')
for li in li_list:
item["_id"] = li.xpath('.//em/text()').extract_first()
item["ZH_name"] = li.xpath('.//a/span[1]/text()').extract_first()
item["notZH_name"] = li.xpath('.//a/span[2]/text()').extract_first().strip('\xa0|/')
item["other_name"] = li.xpath('.//a/span[1]/text()').extract_first()
item["score"] = li.xpath('./div/div[2]/div[2]/div/span[2]/text()').extract_first()
number = li.xpath('./div/div[2]/div[2]/div/span[4]/text()').extract_first()
item["number"] = re.compile(re_path).findall(number)[0]
item["info"] = li.xpath('./div/div[2]/div[2]/p[2]/span/text()').extract_first()
yield item
# 翻页
next_url_partial = response.xpath(
'//*[@id="content"]/div/div[1]/div[2]/span[3]/a/@href').extract_first()
if next_url_partial != None:
next_url = 'https://movie.douban.com/top250' + next_url_partial
yield scrapy.Request(next_url, callback=self.parse)
上面的解析方法使用的是xpath,这个已经没什么好说的了,我想说明一下上面代码的三个地方。
第一个是extract_first()
:我们需要提取出xpath匹配的信息,可以使用extract函数,它返回的是一个所有对应信息的列表,而一般情况下我们需要的往往是列表内的第一个字符串内容,这是就可以使用extract_first()
,它返回的是一个字符串。
第二个是为什么item要使用字典类型?因为我们需要使用mongodb保存数据,使用字典类型很合适,更为重要的是yield能够返回的数据类型有限,具体能返回哪几种可以百度一下,反正是不能返回列表的,字典可以,还可以是爬虫请求得到的响应对象,这在上面的最后一行代码得到了体现。
第三个是yield,和return类似,只不过返回的是一个生成器,可以节省内存。yield item
会将item返回给pipelines.py,我们可以在这个python文件下实现数据处理。下面我会会使用到它来保存数据到数据库。yield scrapy.Request(next_url, callback=self.parse)
会将next_url请求到的响应返回给parse进行解析,所以要设置callback。
保存数据
上面爬取并解析的数据通过yield传给了pipelines.py,所以我们在这里编写保存数据的代码。
import pymongo
# 连接到mongodb数据库
client = pymongo.MongoClient("mongodb://127.0.0.1:27017",username='admin',password='admin123')
# 创建一个豆瓣数据库,并在其下建立一个集合movie_top250
collection = client['douban']['movie_top250']
class DoubanPipeline:
# 这个process_item和parse一样不可修改名称
def process_item(self, item, spider):
# 写入数据库
collection.insert_one(item)
return item
3.settings.py的设置
1.设置日志等级,只显示WARNING及以上级别,加入下面代码:
LOG_LEVEL = "WARNING"
2.设置UA伪装,取消USER_AGENT
的注释,改成你要设置的USER_AGENT:
USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.182 Safari/537.36 Edg/88.0.705.74'
3.打开管道,取消ITEM_PIPELINES
的注释
ITEM_PIPELINES = {
'douban.pipelines.DoubanPipeline': 300,
}
如果有多个管道,可以在这个字典里添加键值对,值表示优先级,值越小,优先级越高,数据会优先通过该管道进行处理。
4.启动爬虫并查看结果
终端运行下列代码启动爬虫:
cd C:\Users\woniu\Desktop\python\scrapy案例\douban
scrapy crawl doubanspider
查看结果:
5.scrapy shell的使用
运行下面的代码:
cd C:\Users\woniu\Desktop\python\scrapy案例\douban
scrapy shell https://movie.douban.com/top250
启动 Scrapy Shell 后,会有一个包含本地的 response 的数据变量,输入 response.body 会得到返回的数据包体,输入 response.xpath() 或 response.css() 对数据进行过滤查询。
我们可以使用shell非常方便地进行代码的调试。输入exit可以退出shell界面。
不得不承认,scrapy初学起来确实很容易被劝退,单单是几个模块就足以让人头晕目眩,我也被劝退了好几回,这次下定决心学下去。如果搞不懂其运行的原理,不妨也动手写一个入门级的爬虫,我相信你也会有不少的感悟(当然我也仅仅才入门)。愿看到这里的朋友能够变得更强,再会~~~