scrapy结合selenium进行动态加载页面内容爬取
动态页面与静态页面
比较常见的页面形式可以分为两种:
- 静态页面
- 动态页面 静态页面和动态页面的区别
使用requests
进行数据获取的时候一般使用的是respond.text
来获取网页源码,然后通过正则表达式提取出需要的内容。
例如:
1 | import requests |
但是动态页面使用上述操作后发现,获取到的内容与实际相差很大。
例如我们打开如下页面:
https://www.aqistudy.cn/historydata/monthdata.php?city=北京
右键选择查看网页源代码
在网页源代码中查找页面中存在的一个数据:2014-02的PM10为155。
这时打开F12查看Elements
可以看到155
在元素中有显示
综上基本可以明白静态页面和动态页面的区别了。
有两种方式可以获取动态页面的内容:
- 破解JS,实现动态渲染
- 使用浏览器模拟操作,等待模拟浏览器完成页面渲染
由于第一个比较困难所以选择方法二
需求分析
获取各个城市近年来每天的空气质量
- 日期
- 城市
- 空气质量指数
- 空气质量等级
- pm2.5
- pm10
- so2
- co
- no2
- o3
使用scrapy
scrapy操作的基本流程如下:
1 | 1.创建项目:scrapy startproject 项目名称 |
创建
打开命令行,输入scrapy startproject air_history
,创建一个名为air_history
的scrapy项目
进入该文件夹,输入scrapy genspider area_spider "aqistudy.cn"
,可以发现在spiders文件夹下多了一个名为area_spider
的py文件
文件目录结构大概如下:
1 | . |
编写item
根据需求编写item如下,spider最后return item
,把值传递给它
1 | import scrapy |
编写爬虫
首先可以得知首页是https://www.aqistudy.cn/historydata/
所以将它赋值给一个名为base_url
的变量,方便后续使用
自动创建的爬出中携带了爬虫的名字,这个name在启动爬虫的时候需要用到,现在暂时用不到
1 | name = 'area_spider' |
####城市信息
进入首页之后可以看到一大批的城市信息,所以我们第一步就是获取有哪些城市
1 | def parse(self, response): |
使用插件XPath Helper
可以对xpath进行一个测试,看看定位的内容是否正确
随意点击一个地区可以发现url变为https://www.aqistudy.cn/historydata/monthdata.php?city=北京
所以url_list
获取到的是需要进行拼接的内容monthdata.php?city=城市名称
city_list
的最后部分是text()
所以它拿到的是具体的文本信息
将获取到的url_list和city_list逐个传递给scrapy.Request
其中url是需要继续爬取的页面地址,city是item中需要的内容,所以将item暂时存放在meta中传递给下个回调函数self.parse_month
月份信息
1 | def parse_month(self, response): |
此步操作获取了每个城市的全部月份信息,并拿到了每个月份的url地址。把上面传递下来的city继续向下传递
最终数据
获取到最终的URL之后,把item实例化,然后完善item字典并返回item
1 | def parse_day(self, response): |
使用中间件实现selenium操作
打开中间件文件middlewares.py
由于我是在服务器上进行爬取,所以我选择使用谷歌的无界面浏览器chrome-headless
1 | from selenium import webdriver |
然后进行页面渲染后的源码获取
request.url
是传递到中间件的url,由于首页是静态页面,所以首页不进行selenium操作
1 | if request.url != 'https://www.aqistudy.cn/historydata/': |
后续的操作也很简单,最后将获取到的内容正确编码后返回给爬虫的下一步
middlewares全部代码
1 | from scrapy import signals |
使用下载器保存item内容
修改pipelines.py
进行文件的存储
1 | import json |
修改settings文件使中间件,下载器生效
打开settings.py
文件
修改以下内容:DOWNLOADER_MIDDLEWARES
使刚才写的middlewares中间件中的类,ITEM_PIPELINES
是pipelines中的类
1 | BOT_NAME = 'air_history' |
运行
使用scrapy crawl area_spider就可以运行爬虫
spider全部代码
1 | # -*- coding: utf-8 -*- |