Scrapy
官方介绍是
An open source and collaborative framework for extracting the data you need from websites.
In a fast, simple, yet extensible way.
意思就是
一个开源和协作框架,用于以快速,简单,可扩展的方式从网站中提取所需的数据。
环境准备
本文项目使用环境及工具如下
- python3
- scrapy
- mongodb
python3 scrapy的安装就不再叙述
mongodb是用来存储数据的nosql非关系型数据库 官方下载地址https://www.mongodb.com/download-center/community?jmp=docs
mongodb图形化管理工具推荐使用nosqlmanager
项目创建
没错,我们还是挑软柿子捏,就爬取最简单的豆瓣电影top250
这个网站几乎是每个学习爬虫的人都会去爬取的网站,这个网站特别有代表性 话不多说,项目开始
创建scrapy项目需要在命令行中进行
切换到工作目录,然后输入指令 scrapy startproject douban
即创建成功,然后使用pycharm打开项目 首先看下目录结构
我们发现项目spiders中只有一个文件,放爬虫的地方怎么会只有一个__init__.py呢
别急我们还需要输入一个命令来创建基本爬虫 打开cmd切换到目录文件夹下的spiders目录
输入 scrapy genspider douban_spider https://movie.douban.com/top250
如下图创建爬虫成功
然后我们打开项目分析目录结构
douban 项目文件夹
spiders 爬虫文件夹
__init__.py
douban_spider.py 爬虫文件
__init__.py
ietms.py 定义items数据结构的地方(即我们爬取内容的属性之类的信息)
middlewares.py 中间件
pipelines.py 定义对于items的处理方法(数据清洗等)(需要在settings中开启pipelines选项)
settings.py 项目的设置文件,定义全局的各种设置(比如头部代理,任务并发量,下载延迟等等)
scrapy.cfg 项目的配置文件(包含一些默认的配置信息)
至此我们的的项目算是创建成功了
确定内容
创建好项目之后下一步就是确定我们要爬取的内容了,然后才可以开始编写我们的items.py文件
首先打开目标网页进行分析
网页中有哪些东西是我们需要的呢?
- 电影排名编号
- 电影名称
- 电影演职员以及年份分类
- 电影星级评分
- 评论人数
- 电影简介
现在就可以根据内容来编写items.py文件了
items.py文件代码编写如下
# -*- coding: utf-8 -*- # Define here the models for your scraped items # # See documentation in: # https://docs.scrapy.org/en/latest/topics/items.html import scrapy class DoubanItem(scrapy.Item): # 示例 # define the fields for your item here like: # name = scrapy.Field() serial_number = scrapy.Field() # 排名 movie_name = scrapy.Field() # 电影名称 introduce = scrapy.Field() # 电影简介基本信息 star = scrapy.Field() # 电影星级评分 evaluate = scrapy.Field() # 电影评论人数 describe = scrapy.Field() # 电影内容简介
内容提取spider文件编写
确定内容之后就是非常关键的spider爬虫文件编写了
测试阶段douban_spider.py文件编写如下:
# -*- coding: utf-8 -*- import scrapy class DoubanSpiderSpider(scrapy.Spider): # 爬虫名字 name = ' douban_spider ' # 允许的域名 爬取url都属于这个域名 allowed_domains = [ ' movie.douban.com ' ] # 起始url start_urls = [ ' https://movie.douban.com/top250/ ' ] def parse(self, response): print (response.text) # 打印响应内容 pass
然后我们需要运行下我们的爬虫看下现在能否出什么信息
打开命令窗口并cd到项目目录下输入命令 scrapy crawl douban_spider
douban_spider是爬虫的名字
运行如下图
发现里面有爬虫的信息也有返回响应的信息,但是我们可以看出来没有我们想要的电影信息,现在怎么办?
稍微学习过爬虫的同学都知道,爬虫是需要修改 USER_AGENT 的,这也是最简单的反爬虫机制,所以我们同样需要去修改我们爬虫的用户代理
去哪找头部代理呢?简单一点的可以直接去百度搜索一个,或者呢我们用浏览器调试台把自己的用户代理复制下来
例如chrome浏览器按F12点击一个资源复制出来用户代理即可不再赘述
打开settings.py文件 找到USER_AGENT修改如下:
# Crawl responsibly by identifying yourself (and your website) on the user-agent # USER_AGENT = 'douban (+http://www.yourdomain.com)' USER_AGENT = ' Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.80 Safari/537.36 '
然后我们再次打开命令窗口并cd到项目目录下输入命令 scrapy crawl douban_spider
发现已经有了我们想要的电影信息
同时每次在命令行运行spider确实不方便,我们可以在项目中添加一个main.py的启动文件如下
main.py编写代码:
from scrapy import cmdline cmdline.execute( ' scrapy crawl douban_spider ' .split())
运行,发现就得到了与命令行运行一样的效果了
接下来的工作就是 数据处理 了,提取出我们想要的信息 继续编写spider.py文件
对于数据的提取我们使用xpath定位 先来观察目标网站的元素 我们可以看到top250电影中每一页有25个电影信息 并且每个电影信息都是一个列表 li
xpath有好多种写法 我们可以审查元素然后编写xpath定位,或者呢直接用chrome也可以直接获取某元素的xpath路径
例如使用某xpath浏览器插件来找我们需要的元素 我们首先先找到每个电影的定位
如图我们编写 //ol[@class='grid_view']/li/div[@class='item'] 就可以定位到当前每个电影 其实我们简单点直接写 //ol/li 也可以,但是我们最好直接精确一点 xpath语法如下
表达式 | 描述 |
---|---|
nodename | 选取此节点的所有子节点。 |
/ | 从根节点选取。 |
// | 从匹配选择的当前节点选择文档中的节点,而不考虑它们的位置。 |
. | 选取当前节点。 |
.. | 选取当前节点的父节点。 |
@ | 选取属性。 |
然后同理,我们就可以找到电影排名,名称,评论等等信息的xpath, 接下来在spider.py文件中引用我们的 items.py中编写的DoubanItem类 然后完成对象属性的赋值
spider.py文件代码:
# -*- coding: utf-8 -*- import scrapy from douban.items import DoubanItem class DoubanSpiderSpider(scrapy.Spider): # 爬虫名字 name = ' douban_spider ' # 允许的域名 爬取url都属于这个域名 allowed_domains = [ ' movie.douban.com ' ] # 起始url start_urls = [ ' https://movie.douban.com/top250/ ' ] # 默认解析方法 def parse(self, response): # 注意在python语句中使用xpath如 注意与原来语句单双引号的问题 movie_list=response.xpath( " //ol[@class='grid_view']/li/div[@class='item'] " ) for movie_item in movie_list: douban_item = DoubanItem() # xpath语句最后的text()是获取当前xpath的内容 # scrapy get() getall()方法获得xpath路径的值 两种方法不同请百度 douban_item[ ' serial_number ' ] = movie_item.xpath( " .//em/text() " ).get() douban_item[ ' movie_name ' ] = movie_item.xpath( " .//span[@class='title']/text() " ).get() # 介绍的内容非常不规范并且有好多行,首先使用getall()来获取,然后我们要对其进行处理 content = movie_item.xpath( " .//div[@class='bd']/p[1]/text() " ).getall() # 处理 contient_introduce= '' for conitem in content: content_s = '' .join(conitem.split()) contient_introduce =contient_introduce+content_s+ ' ' # 赋值 douban_item[ ' introduce ' ] = contient_introduce douban_item[ ' star ' ] = movie_item.xpath( " .//span[@class='rating_num']/text() " ).get() douban_item[ ' evaluate ' ] = movie_item.xpath( " .//div[@class='star']/span[4]/text() " ).get() douban_item[ ' describe ' ] = movie_item.xpath( " .//div[@class='bd']/p[2]/span/text() " ).get() # 我们需要把获取到的东西yield到douban_item中,否则我们的管道pipelines.py无法接收数据 yield douban_item # 我们需要自动翻页到下一页去解析数据 next_linkend=response.xpath( " //span[@class='next']/a/@href " ).get() # 判断next_linkend是否存在 if next_linkend: next_link = ' https://movie.douban.com/top250/ ' + next_linkend # 同样需要yield提交到调度器中 同时添加一个回调函数(刚刚编写的数据提取函数) yield scrapy.Request(next_link,callback=self.parse)
数据存储
我们可以使用命令直接将数据保存到 json或者csv文件如下
还是使用命令行 cd到项目目录
输入命令 scrapy crawl douban_spider -o test.json 就可以得到一个json文件
输入命令 scrapy crawl douban_spider -o test.csv 就可以得到一个csv文件
这个csv文件可以直接用excel打开浏览,但是我们会发现存在乱码,我们可以先用notepad++打开文件改下编码方式然后保存再用excel打开即可
存储到数据库
接下来我们需要对pipelines.py进行编写,将数据存储到mongodb中
注意 我们需要在setting.py中将 ITEM_PIPELINES 的注释关掉,这样才能正常的运行pipelines.py
pipelines.py代码:
# -*- coding: utf-8 -*- # Define your item pipelines here # # Don't forget to add your pipeline to the ITEM_PIPELINES setting # See: https://docs.scrapy.org/en/latest/topics/item-pipeline.html import pymongo # 连接本地数据库 远程也可以 myclient = pymongo.MongoClient( " mongodb://localhost:27017/ " ) # 数据库名称 mydb = myclient[ " douban " ] # 数据表名称 mysheet = mydb[ " movie " ] class DoubanPipeline(object): # 此中的item就是刚刚yield回来的 def process_item(self, item, spider): data = dict(item) # 插入数据 mysheet.insert(data) return item
现在运行 main.py 数据就存储到数据库之中了,我们可以打开数据库查看数据
至此,我们的爬虫项目可以说已经完成了。
爬虫伪装
- ip代理中间件
- user-agent中间件
ip代理需要购买服务器然后可以使用先不提了
我们尝试下user-agent中间件
编写middlewares.py再最后新加入我们自己编写的类(文件最上端要 import random):
class my_useragent(object): def process_request(self,request,spider): USER_AGENT_LIST = [ " Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; AcooBrowser; .NET CLR 1.1.4322; .NET CLR 2.0.50727) " , " Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; Acoo Browser; SLCC1; .NET CLR 2.0.50727; Media Center PC 5.0; .NET CLR 3.0.04506) " , " Mozilla/4.0 (compatible; MSIE 7.0; AOL 9.5; AOLBuild 4337.35; Windows NT 5.1; .NET CLR 1.1.4322; .NET CLR 2.0.50727) " , " Mozilla/5.0 (Windows; U; MSIE 9.0; Windows NT 9.0; en-US) " , " Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0; .NET CLR 3.5.30729; .NET CLR 3.0.30729; .NET CLR 2.0.50727; Media Center PC 6.0) " , " Mozilla/5.0 (compatible; MSIE 8.0; Windows NT 6.0; Trident/4.0; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; .NET CLR 1.0.3705; .NET CLR 1.1.4322) " , " Mozilla/4.0 (compatible; MSIE 7.0b; Windows NT 5.2; .NET CLR 1.1.4322; .NET CLR 2.0.50727; InfoPath.2; .NET CLR 3.0.04506.30) " , " Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN) AppleWebKit/523.15 (KHTML, like Gecko, Safari/419.3) Arora/0.3 (Change: 287 c9dfb30) " , " Mozilla/5.0 (X11; U; Linux; en-US) AppleWebKit/527+ (KHTML, like Gecko, Safari/419.3) Arora/0.6 " , " Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.2pre) Gecko/20070215 K-Ninja/2.1.1 " , " Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9) Gecko/20080705 Firefox/3.0 Kapiko/3.0 " , " Mozilla/5.0 (X11; Linux i686; U;) Gecko/20070322 Kazehakase/0.4.5 " , " Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.8) Gecko Fedora/1.9.0.8-1.fc10 Kazehakase/0.5.6 " , " Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.56 Safari/535.11 " , " Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_3) AppleWebKit/535.20 (KHTML, like Gecko) Chrome/19.0.1036.7 Safari/535.20 " , " Opera/9.80 (Macintosh; Intel Mac OS X 10.6.8; U; fr) Presto/2.9.168 Version/11.52 " , ] agent = random.choice(USER_AGENT_LIST) request.headers[ ' User_Agent ' ] = agent
然后去 settings.py 中开启中间件并修改为我们刚刚创建的类如下图
然后再运行 main.py 就都OK了。