1.前言

目标网站:武汉市环境保护局(http://hbj.wuhan.gov.cn/viewAirDarlyForestWaterInfo.jspx)。scrapy对接selenium模块抓取空气质量日报数据,需要搭建selenium运行的相应环境,大概搭建方法参见:selenium基本使用;主要是模块的安装和驱动的下载与安装,windows下好像不支持Chorme的无头浏览器,但是有界面的浏览器速度会相对较慢,有条件搭建linux的,用linux下的Chorme headless驱动会快很多;其他的,像火狐等主流浏览器也有对应的驱动,环境搭建差不多,本文用的就是windows下谷歌的驱动(慢就慢点吧);Phantomjs无头浏览器好像现在不能用了。

注意:Chorme浏览器的驱动下载需要结合自己电脑的浏览器版本下载对应的驱动,不然可能驱动用不了。

2.任务分析

抓取武汉市环境保护局的空气质量日报,该网站数据是采用异步加载的;抓包分析可知,整个过程都是对同一个url进行抓取(注:这是一个点,后续编码需要考虑的);因为是用selenium点开网页,所以不需要考虑POST还是GET请求。

3.代码逻辑

3.1 创建scrapy项目

基础的项目创建、爬虫创建及创建后项目的文件结构等内容,就不一一写了,基本使用网上有很多博文,直接上正文了。

3.2 明确抓取字段

来到items.py文件,明确待抓取字段。

# -*- coding: utf-8 -*-
import scrapy class EnvprotectItem(scrapy.Item): # 日期
date = scrapy.Field()
# 点位
loca = scrapy.Field()
# SO2
SO_2 = scrapy.Field()
# NO2
NO_2 = scrapy.Field()
# 吸入颗粒
PMIO = scrapy.Field()
# CO
CO_1 = scrapy.Field()
# O3
O3_d = scrapy.Field()
# 细颗粒物
PM25 = scrapy.Field()
# 空气质量指数
AQIe = scrapy.Field()
# 首要污染物
prmy = scrapy.Field()
# AQI级别
AQIl = scrapy.Field()
# AQI类别
AQIt = scrapy.Field()

3.3 编写爬虫逻辑

到spiders文件夹下的爬虫文件中,开始编写爬虫逻辑。

从第一次selenium请求后的结果中,解析出共多少条数据,以此确定共多少个页面;

从返回的网页源代码中解析数据;

模拟点击“下一页”,获取数据后,继续解析数据,直至解析完所有页面;

selenium模拟点击操作的代码都在middlewares.py的下载中间件中编写;

scrapy会默认过滤掉重复请求(即目标url相同),我们是对同一目标url爬取,因此注意重复请求的设置。

# -*- coding: utf-8 -*-
import math
import scrapy
from EnvProtect.items import EnvprotectItem class ProtectenvSpider(scrapy.Spider):
name = 'ProtectEnv'
# allowed_domains = ['hbj.wuhan.gov.cn']
# start_urls = ['http://hbj.wuhan.gov.cn/']
page=1
pages=1
# 目标url
base_url = 'http://hbj.wuhan.gov.cn/viewAirDarlyForestWaterInfo.jspx' def start_requests(self):
yield scrapy.Request(
url=self.base_url,
callback=self.parse,
dont_filter=True, # 设置不过滤重复请求,scrapy默认过滤重复请求
meta={'index':1} # 该参数判断是否为第一次请求
) def parse(self, response):
"""
第一次请求返回结果中解析出,指定时间段(在middlewares.py文件中指定,后续介绍)内一共有多少条数据;
由于一直是对同一个页面进行爬取(翻页时url没变,数据变了),数据共多少条(页)确定一次就够了
:param response:
:return:
"""
if response.meta['index']:
counts = response.xpath("//div[@class='serviceitempage fr']/span[@class='fl']/text()").extract_first()
counts = int(counts.split(' ')[0])
self.pages = math.ceil(counts / 22) # 确定一共多少个页面 # 解析数据
node_list = response.xpath('//*[@id="tableForm"]/div/div[3]/table/tbody/tr')[1:]
for node in node_list:
item = EnvprotectItem()
item['date'] = node.xpath("./td[1]/text()").extract_first()
item['loca'] = node.xpath("./td[2]/text()").extract_first()
item['SO_2'] = node.xpath("./td[3]/text()").extract_first()
item['NO_2'] = node.xpath("./td[4]/text()").extract_first()
item['PMIO'] = node.xpath("./td[5]/text()").extract_first()
item['CO_1'] = node.xpath("./td[6]/text()").extract_first()
item['O3_d'] = node.xpath("./td[7]/text()").extract_first()
item['PM25'] = node.xpath("./td[8]/text()").extract_first()
item['AQIe'] = node.xpath("./td[9]/text()").extract_first()
item['prmy'] = node.xpath("./td[10]/text()").extract_first()
item['AQIl'] = node.xpath("./td[11]/text()").extract_first()
item['AQIt'] = node.xpath("./td[12]/text()").extract_first()
yield item # 编写爬虫停止运行逻辑
if self.page < self.pages:
self.page += 1
yield scrapy.Request(
url = self.base_url,
callback=self.parse,
dont_filter=True, # 不过滤重复请求,scrapy默认过滤重复请求
meta={'index':0}
)

3.4 编写下载中间件

selenium的所有操作的代码都写在下载中间件中。

# -*- coding: utf-8 -*-
import time
import scrapy
from selenium.webdriver.common.action_chains import ActionChains
from selenium import webdriver
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By from EnvProtect.settings import USER_AGENTS as ua class EnvprotectDownloaderMiddleware(object): def __init__(self):
"""
第一页时,不需要点击跳转;其他页面需要模拟点击跳转来获取数据
"""
self.index = 1 def process_request(self, request, spider): if request.url == 'http://hbj.wuhan.gov.cn/viewAirDarlyForestWaterInfo.jspx': self.driver = webdriver.Chrome() # 实例化一个谷歌浏览器
self.driver.get(request.url) # 请求页面
wait = WebDriverWait(self.driver, 30) # 等待页面数据加载,等待30s
try:
# 选择城区
wait.until(EC.frame_to_be_available_and_switch_to_it((By.ID, "iframepage"))) # 等待iframe标签出现
options = self.driver.find_element_by_xpath("//select[@id='typedictionary']/option[2]")
options.click() # 选择时间
self.driver.find_element_by_id('cdateBeginDic').send_keys('2018-11-01')
self.driver.find_element_by_id('cdateEndDic').send_keys('2019-01-20') # 点击查询
self.driver.find_element_by_xpath("//a[@href='#' and @onclick='toQuery(2);']").click()
time.sleep(5) # 指定页面
if not self.index == 1:
self.index += 1 # 第一个页面不用跳转,其他页面需要跳转过去
self.driver.find_element_by_id('goPag').send_keys(str(self.index))
self.driver.find_element_by_id('_goPag').click() # 跳转到该页面
except:
print("Error!")
self.driver.quit() # 构造返回response
html = self.driver.page_source
self.driver.quit()
response = scrapy.http.HtmlResponse(url=request.url, body=html, request=request, encoding='utf-8') return response

3.5 数据保存逻辑

在pipelines文件中编写数据保存逻辑,此处将数据保存为excel文件。

# -*- coding: utf-8 -*-
from openpyxl import Workbook class EnvprotectPipeline(object): def __init__(self):
# 创建excel表格保存数据
self.workbook = Workbook()
self.booksheet = self.workbook.active
self.booksheet.append(['日期', '检测点位', '二氧化硫',
'二氧化氮', '可吸入颗粒物', '一氧化碳',
'臭氧', '细颗粒物', '空气质量指数',
'首要污染物', 'AQI指数级别', 'AQI指数类别']) def process_item(self, item, spider): DATA = [
item['date'], item['loca'], item['SO_2'],
item['NO_2'], item['PMIO'], item['CO_1'],
item['O3_d'], item['PM25'], item['AQIe'],
item['prmy'], item['AQIl'], item['AQIt']
] self.booksheet.append(DATA)
self.workbook.save('./results.xls')
return item

3.6  其他

1.在settings.py文件中打开对应的pipe通道;

2.关闭robot.txt协议

4.完整代码

参见:github地址

scrapy结合selenium抓取武汉市环保局空气质量日报的更多相关文章

  1. [转]使用scrapy进行大规模抓取

    原文:http://www.yakergong.net/blog/archives/500 使用scrapy有大概半年了,算是有些经验吧,在这里跟大家讨论一下使用scrapy作为爬虫进行大规模抓取可能 ...

  2. 在Scrapy项目【内外】使用scrapy shell命令抓取 某网站首页的初步情况

    Windows 10家庭中文版,Python 3.6.3,Scrapy 1.5.0, 时隔一月,再次玩Scrapy项目,希望这次可以玩的更进一步. 本文展示使用在 Scrapy项目内.项目外scrap ...

  3. scrapy定时执行抓取任务

    在ubuntu环境下,使用scrapy定时执行抓取任务,由于scrapy本身没有提供定时执行的功能,所以采用了crontab的方式进行定时执行: 首先编写要执行的命令脚本cron.sh #! /bin ...

  4. Python爬虫实战八之利用Selenium抓取淘宝匿名旺旺

    更新 其实本文的初衷是为了获取淘宝的非匿名旺旺,在淘宝详情页的最下方有相关评论,含有非匿名旺旺号,快一年了淘宝都没有修复这个. 可就在今天,淘宝把所有的账号设置成了匿名显示,SO,获取非匿名旺旺号已经 ...

  5. selenium抓取动态网页数据

    1.selenium抓取动态网页数据基础介绍 1.1 什么是AJAX AJAX(Asynchronouse JavaScript And XML:异步JavaScript和XML)通过在后台与服务器进 ...

  6. selenium抓取视频

    今天闲着没事,用selenium抓取视频保存到本地,只爬取了第一页,只要小于等于5分钟的视频... 为什么不用requests,没有为什么,就因为有些网站正则和xpath都提取不出来想要的东西,要么就 ...

  7. scrapy下载中间件结合selenium抓取全国空气质量检测数据

    1.所需知识补充 1.下载中间件常用函数 process_request(self, request, spider): 当每个request通过下载中间件是,该方法被调用 process_reque ...

  8. 用python+selenium抓取知乎今日最热和本月最热的前三个问题及每个问题的首个回答并保存至html文件

    抓取知乎今日最热和本月最热的前三个问题及每个问题的首个回答,保存至html文件,该html文件的文件名应该是20160228_zhihu_today_hot.html,也就是日期+zhihu_toda ...

  9. 用python+selenium抓取微博24小时热门话题的前15个并保存到txt中

    抓取微博24小时热门话题的前15个,抓取的内容请保存至txt文件中,需要抓取排行.话题和阅读数 #coding=utf-8 from selenium import webdriver import ...

随机推荐

  1. 神舟+win10+ubuntu16.04+256GSSD+1THHD双系统安装加openssl踩坑之旅

    上海最近搞活动调休,要搞深度学习,win上还是不方便,准备弄个ubuntu.于是有以下回忆文字. 在机器上装了个双系统.花了两天.再也不想玩了. 准备用ubuntu来做深度学习的. 本文写于2019年 ...

  2. Python网络爬虫之cookie处理、验证码识别、代理ip、基于线程池的数据爬去

    本文概要 session处理cookie proxies参数设置请求代理ip 基于线程池的数据爬取 引入 有些时候,我们在使用爬虫程序去爬取一些用户相关信息的数据(爬取张三“人人网”个人主页数据)时, ...

  3. C++学习笔记3_类.和相关函数

    1. 类*在C++中,struct和class没有明显差别,不同C#,class一定要new(手动开辟内存)出来struct Hero{ char name[64]; int sex;}void pr ...

  4. Unity2-投影方式

  5. [考试反思]1012csp-s模拟测试70:盘旋

    这套题比较烂... 上来看到T2是原题,一想上一次考试遇到原题就不换,这次应该也是,于是直接开始码,码了一半然后换题了 T1打表找规律或者推式子都不难... T2水的一匹暴力剪枝即可,但是我并不知道数 ...

  6. GERALD07加强版:lct,主席树,边化点

    Description:N个点M条边的无向图,询问保留图中编号在[l,r]的边的时候图中的联通块个数. 传送门. lct这么神仙的东西一个题解都不写怎么行??? 神仙思路啊. 其实不是很难但是的确不容 ...

  7. [考试反思]0822NOIP模拟测试29:延续

    想保持优秀很困难 但是想持续垫底却很简单 但是你不想垫底的话持续垫底也很容易... 分AB卷,A卷共15人. skyh,tdcp,kx155,B哥145... 我:35,倒数第一. 板子专题,爆零快乐 ...

  8. CSPS模拟 77

    %%两位AK爷zkt和skyh T1 位间独立,分别讨论 T2 维护标记,代替移位 T3 同一点对,多种联通,没法搞. 发现最多四路连通,考虑容斥. 显然的奇加偶减. 发现统计某种颜色的点之间的联通数 ...

  9. Spring Cloud Gateway使用简介

    Spring Cloud Gateway是类似Nginx的网关路由代理,有替代原来Spring cloud zuul之意: Spring 5 推出了自己的Spring Cloud Gateway,支持 ...

  10. Vue计算属性缓存(computed) vs 方法

    Vue计算属性缓存(computed) vs 方法 实例 <div id="example"> <p>Original message: "{{ ...