python爬虫入门,获取全国气象站24小时整点气象数据(一)
python爬虫入门,获取全国气象站24小时整点气象数据(二)
上一节我们已经成功获取了单个城市的天气数据,接下来我们就要扩展到获取全国所有城市地区的气象数据,很简单,一步一步来。
3.将数据存储到数据库
我们的目标是收集全国所有气象站每天24小时整点数据,数据量很大,所以需要将数据存储到数据库中。我们选择sqlite。
对应的python库是sqlite3。
首先建立数据库
数据库设计如下
- 地区编码,positionId,int
- 地区名,name,text
- 小时,date_time,date
- 温度,temperature, int
- 降雨量,rain,int
- 相对湿度,humidity,int
- 风向,windDirection,int
- 风速,windPower,int
- 全名,fullName,text
- 插入时间,createTime,text
建库建表代码:
import sqlite3
conn = sqlite3.connect("demo.db") #直接在同级目录下创建名为demo的数据库
c = conn.cursor()
c.execute('''create table weather
(positionId int not null,
name text not null,
date_time date not null,
temperature int,
rain int,
humidity int,
windDirection int,
windPower int,
fullName text not null,
createTime text not null DEFAULT (datetime('now','localtime')));''')
各个字段都在上一节获取到了。我们还需要获取fullname字段,地区全名,即如图所示的湖北>武汉>城区。需要再写个函数获取:
def getPositionName(soup, num): #soup:beautiful的soup对象,num城市编码
position_name = soup.find(class_="crumbs")
name = []
for i in range(len(position_name.find_all("a"))):
name.append(position_name.find_all("a")[i].text)
name.append(position_name.find_all("span")[len(position_name.find_all("span"))-1].text)
[0].text, position_name.find_all("a")[1].text,position_name.find_all("span")[1].text,position_name.find_all("span")[2].text
name_str = "-".join(name)
return name_str
数据库建好了,下面编写代码将数据写入表中。先将节爬虫代码抽象成函数spider:
def spider(url,num): #url,num:城市编码
html = urllib.request.urlopen(url).read()
soup = BeautifulSoup(html,'html.parser',from_encoding='utf-8')
res_data = soup.findAll('script')
weather_data = res_data[4]
fullName = getPositionName(soup, num)
for x in weather_data:
weather1 = x
index_start = weather1.find("{")
index_end = weather1.find(";")
weather_str = weather1[index_start:index_end]
weather = eval(weather_str)
weather_dict = weather["od"]
weather_date = weather_dict["od0"]
weather_position_name = weather_dict["od1"]
weather_list = list(reversed(weather["od"]["od2"]))
#将数据存入数据库
save_in_db(num,weather_date, weather_position_name, weather_list, fullName)
return True
将数据存入数据库的函数:
def save_in_db(num,weather_date, weather_position_name, weather_list, fullName):
insert_list = []
for item in weather_list:
#od21小时,od22温度,od26降雨,od24风向,od25风力
weather_item = {}
weather_item['time'] = item['od21']
weather_item['temperature'] = item['od22']
weather_item['rain'] = item['od26']
weather_item['humidity'] = item['od27']
weather_item['windDirection'] = item['od24']
weather_item['windPower'] = item['od25']
weather_item['od23'] = item['od23']
insert_list.append(weather_item)
conn = sqlite3.connect("demo.db")
c = conn.cursor()
for item in insert_list:
c.execute("insert into weather (positionId,name,date_time,temperature,rain,humidity,windDirection,windPower,fullName) \
values(?,?,?,?,?,?,?,?,?)",(num,weather_position_name,item['time'],item['temperature'],item['rain'],item['humidity'],item['windDirection'],item['windPower'],fullName))
conn.commit()
conn.close()
使用武汉的url测试一下
if __name__ == "__main__":
spider("http://www.weather.com.cn/weather1d/101200101.shtml",101200101)
让我们看看数据库,已经成功写入了24个整点的天气数据4.寻找url规律
接下来就是获取全国的城市地区的数据。
数据来自网页,网页来自url请求。通过观察url,很容易就发现了规律。
http://www.weather.com.cn/weather1d/101200101.shtml
weather1d是1天的数据
101200101是城市编码,比如武汉就是101200101
不同城市的url只有最后的城市编码不一样,让我们观察下其他城市编码
湖北-武汉-城区:101'20'01'01
湖北-武汉-蔡甸:101'20'01'02
湖北-武汉-黄陂:101'20'01'03
湖北-武汉-江夏:101'20'01'05
--
湖北-襄阳-城区:101'20'02'01
--
湖北-江夏-城区:101'20'05'01
--
浙江-杭州-城区:101'21'01'01
--
四川-成都-城区:101'27'01'01
--
日本-札幌:103'56'01'00
大家是不是已经发现规律了,显然编码规律如下
一共九位数xxx'xx'xx'xx
xxx(国家)xxx(省份)xx(城市)xx(地区)
现在知道编码规律了,只需要按规律发送url,即可获取全国所有站点的数据,是不是很棒棒,哈哈!
我用了一个笨办法来遍历url,通过三个while循环来依次递增省份、城市、地区的编码,代码如下:
def start():
base_url = "http://www.weather.com.cn/weather1d/101"
province_num = 1
while (province_num < 80):
flag = True
city_num = 1
while (city_num < 20):
position_num = 1
while (position_num < 30):
num_str = str(province_num).zfill(2) + str(city_num).zfill(2) + str(position_num).zfill(2)
url = base_url + num_str + ".shtml"
time.sleep(2)
#print(url)
flag = spider(url, num_str)
if (flag == False):
break
position_num += 1
pass
if (flag == False and position_num == 1):
break
city_num += 1
pass
if (flag == False and position_num == 1 and city_num == 1):
break
province_num += 1
一切都完成了,下面,爬虫,启动!
if __name__ == "__main__":
start()
看看数据库看看全国一天大概会产生多少数据呢,今天的最低温度是多少呢
select count(DISTINCT positionid) from weather --全国一共有多少地区
select count(*) from weather --全国一天产生的数据量
select * from weather where temperature = (select min(temperature) from weather) --温度最低的地区
结果分别如下:
3024
75600
50705 呼中 7 -36 0 68 东南风 1 黑龙江-大兴安岭-呼中 2018-02-15 21:15:36
可以看到中国天气网大概有3024个地区有天气信息,每天产生75600条数据。
截止到年三十10点,国内最低温度位于黑龙江-大兴安岭-呼中,达到了零下36度,真是瑟瑟发抖呀。
5.总结
- 地址编码的遍历代码写的太笨,而且有地区遗漏,比如直辖市和景点。可以有更好的实现。
- 网页解析代码部分,由于我挖了一下坑,可能无法完美运行,需要的同学可以私信讨论。
- 数据库的data_time字段目前只是小时,可以扩展成时间戳,方便之后的分析。