报告分析需要历史气象数据,查询到天气网上面有历史天气数据,从2011年到2018年,第一次接触爬虫,在网上找了爬取天气网历史数据的python源码,利用bs4库,但是实际操作中发现soup.select( )函数返回的列表总是[ ] (空),查询发现天气网目前使用的是javascript写的动态页面,可能是为了防止爬虫接入。经过查资料又找到了一种爬取动态页面的方法,经尝试方法有效,写个博客记录一下,也算是感谢网络上分享知识的网友,也便于自己日后查询使用方便。
先贴上完整的代码,再附上自己简单的理解,最后是附上自己的参考链接。
语言:python3,用到的库:bs4、pandas、selenium
完整源代码如下:
from bs4 import BeautifulSoup
import pandas as pd
from selenium import webdriver
for month in range(1,13,1):
print("开始爬取"+"2016年"+str(month)+"月的数据...")
driver=webdriver.Ie()
#driver.maximize_window()
if month < 10:
url='http://lishi.tianqi.com/shuangpai/2016'+'0'+str(month)+'.html'
else:
url='http://lishi.tianqi.com/shuangpai/2016'+str(month)+'.html'
driver.get(url)
html_text=driver.page_source
soup = BeautifulSoup(html_text, 'html.parser')
weather_list=soup.select('div[class="tqtongji2"]')
for weather in weather_list:
ul_list = weather.select('ul')
data_all=[]
for i in ul_list:
li_all=i.select("li")
data=[]
for j in li_all:
data.append(j.text)
data_all.append(data)
weather=pd.DataFrame(data_all)
weather.columns=["日期","最高气温","最低气温","天气","风向","风力"]
weather.drop([0],inplace=True)
if month==1:
weather.to_csv("2016shuangpai.csv",mode='a',index=False,header=True,encoding="utf_8_sig")
else:
weather.to_csv("2016shuangpai.csv",mode='a',index=False,header=False,encoding="utf_8_sig")
print("2016年"+str(month)+"月的数据爬取完毕")
driver.close()
原理:通过借助iedriverserver.exe操纵ie浏览器打开指定url的网页,浏览器就会获得网页的源码,接下来就和爬取静态网页的原理相同了,只需要利用bs4库中的BeautifulSoup解析源码,获取指定的数据就可以了。具体步骤和注意事项有:
1.下载iedriverserver.exe,也可以用Chrome、Firefox浏览器下载对应的chromedriver.exe和firefoxdriver.exe,我试过Chrome,发现打开浏览器后请求url页面有时能打开,有时打不开,就选用了ie,ie使用基本正常。此处要注意,浏览器驱动的下载需要和浏览器是对应的版本,版本不同会报错,不过我没试过不同版本,都是按照网上说的下载的对应版本,我在下面贴出我查找到的ie和chrome的驱动下载地址,firefox的大家自行搜索。务必注意版本对应问题。其次下载后的驱动解压后把可执行文件放在和python脚本同一个目录下,当然放在任意目录通过也可以配置环境变量调用。运行程序是可能还需要关闭防火墙,避免防火墙组织驱动的自动运行。
iedriverserver.exe下载地址:http://selenium-release.storage.googleapis.com/index.html
chromedriver下载地址:http://npm.taobao.org/mirrors/chromedriver/
2.下面是对代码的说明:
driver=webdriver.Ie()#利用驱动打开ie浏览器
driver.maximize_window()#浏览器窗口最大化,不必要步骤
if month < 10:#对网页进行批处理爬取,可以找到url的规律,也可以写出需要爬取的url构建一个列表
url='http://lishi.tianqi.com/shuangpai/2016'+'0'+str(month)+'.html'
else:
url='http://lishi.tianqi.com/shuangpai/2016'+str(month)+'.html'
driver.get(url)#在浏览器地址栏访问url
html_text=driver.page_source#获取加载的网页的所有源代码
soup = BeautifulSoup(html_text, 'html.parser')#对源代码进行解析,'html.parser'为python库函数自带的解析器
对源代码进行解析后,就相当于爬取静态页面了,根据使用浏览器事先查看的页面的数据所在位置访问即可,下面结合我爬取的页面说明我的数据的获取。
浏览器页面如上图,右击查看源代码。
首先,解析后的源代码使用select( ) 方法获取div标签,class=“tqtongji2”,得到的是一个列表list,此处列表只有一个元素
weather_list=soup.select('div[class="tqtongji2"]')#首先,解析后的源代码使用select( ) 方法获取div标签,class=“tqtongji2”,得到的是一个列表list,此处列表只有一个元素
for weather in weather_list:
ul_list = weather.select('ul')
#从div标签中选择ul标签
data_all=[]
for i in ul_list:
li_all=i.select("li")
#每个ul标签下有一组数据获取行标题
data=[]
for j in li_all:
data.append(j.text)
#把所有的li数据按顺序放在数组中
data_all.append(data)
#把每个ul的数据按照顺序放在数组中
weather=pd.DataFrame(data_all)
#建立dataframe
weather.columns=["日期","最高气温","最低气温","天气","风向","风力"]
#给dataframe添加行标题
weather.drop([0],inplace=True)
#删除第0行,第0行也即是一个ul标签不是数据
if month==1:
weather.to_csv("2016shuangpai.csv",mode='a',index=False,header=True,encoding="utf_8_sig")
else:
weather.to_csv("2016shuangpai.csv",mode='a',index=False,header=False,encoding="utf_8_sig")
#将数据保存到到csv文件中去,mode=‘a’采用追加模式,若是不写默认为w,采用重写覆盖模式,编码为了使得中文不乱码
print("2016年"+str(month)+"月的数据爬取完毕")
driver.close()
关闭浏览器,避免计算机打开浏览器窗口过多,有限制或者响应速度减慢