目标网站:http://www.weather.com.cn/textFC/hb.shtml
我重点分析解析网页这个部分,请求网页这个模块就跳过吧。
打开浏览器的检查,找到我们想要的数据所存放的节点。
可以发现,这张网页的所有省份里面的城市信息是存放在(div class =‘conMidtab’)这个节点里面
可以用BeautiSoup来定位到这个节点假设我们已经获取了网页的文本信息并存放在html这个变量里面。
#解析网页我之所以用html5lib主要是因为在港澳台的天气网页中,网页代码不规范没有table的闭合标签
#html5lib的容错能力是最强的
soup = BeautifulSoup(html,'html5lib')
#直接定位到所有省份天气的节点。
conMidtab = soup.find('div',class='conMidtab')
继续检查找到一个省份的数据信息存放的节点,发现信息的存放在table这个标签里面
因为div class=conMidtab这个节点里面存放了所有省份的天气信息,现在我们要定位在一个省份的信息
tables = conMidtab.find_all('table')
继续检查,找到一个city的信息。
city信息是放在table下面的tr标签中,但是前面两个tr标签并没有存放信息,所以在进行遍历的时候我们要把前面两个tr用切片去掉。
for table in tables:
trs = table.find_all('tr')[2:]
然后我们来分析table下面的第三个tr,城市天气信息是放在每一个td中的。但是tr下面的第一个td存放的是一个省份名称。我们用河北省来分析,因为北京市和北京城市是同名的
总之就是第三个tr下面的第一个td里面存放的是省份不是city,而我们在遍历到第四个tr的时候,第一个td存放的就是city。所以我在处理这个部分的时候使用的是倒序取。代码如下,同理在找最高温度的时候,我也是采用倒序这个笨方法。
for tr in trs:
#找到所有的td标签
tds = tr.find_all('td')
#[-8]是td中存放城市名称的位置
city_td = tds[-8]
#city_td是一个标签类型,我们把他变成一个列表类型,再取第一个城市名称变成一个字符串。
city = list(city_td.stripprd_strings)[0]
max_temp_td = tds[-5]
max_temp = list(max_temp_td.stripprd_strings)[0]
#如果想把爬取的城市信息存放在本地,可以用with open as 这个方法。
with open('temp.text','a',encoding='utf-8') as f:
f.write('{:^10}\t{:^4}\n'.format(city,max_temp,chr(12288)))
f.flush()
下面就是解析一张网页的全部过程。用定义函数把这个过程封装起来。
def parserHTML(url):
headers = {
"User-Agent":"Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36"
}
r =requests.get(url,headers=headers)
r.encoding = r.apparent_encoding
html = r.text
soup=BeautifulSoup(html,'html5lib')
#定位到所有存放天气和城市信息大标签
conMidtab = soup.find('div',class_='conMidtab')
#定位到存放一个省份的天气信息的标签,还需要在每一个省份中找到每一个城市的信息。
tables = conMidtab.find_all('table')
for table in tables:
trs = table.find_all('tr')[2:]
for tr in trs:
tds = tr.find_all('td')
city_td = tds[-8]
city = list(city_td.stripped_strings)[0]
temp_td = tds[-5]
max_temp = list(temp_td.stripped_strings)[0]
with open('temp.text','a',encoding='utf-8') as f:
f.write('{:^10}\t{:^4}\n'.format(city,min_temp,chr(12288)))
f.flush()
如果我们想爬取中国所有city’的最高温度,还要然程序自动翻页。首先找到网页翻页的规律,或者用笨办法把所有的网页列下来,然后一个一个的遍历。我采用的是笨办法。
华北:http://www.weather.com.cn/textFC/hb.shtml
东北:http://www.weather.com.cn/textFC/db.shtml
华东:http://www.weather.com.cn/textFC/hd.shtml
def main():
urls=[
'http://www.weather.com.cn/textFC/hb.shtml',
'http://www.weather.com.cn/textFC/db.shtml',
'http://www.weather.com.cn/textFC/hd.shtml',
'http://www.weather.com.cn/textFC/hz.shtml',
'http://www.weather.com.cn/textFC/hn.shtml',
'http://www.weather.com.cn/textFC/xb.shtml',
'http://www.weather.com.cn/textFC/xn.shtml',
'http://www.weather.com.cn/textFC/gat.shtml'
]
for url in urls:
parserHTML(url)
if __name__=='__main__':
main()
如何进行找到气温最高的前十城市呢。我的思路是:
1.是要把我们爬取的下来的信息,放在一个空列表 Temp=[] 里面。可以在解析函数之前定义一个空列表。
#把max_temp变成一个整型,方便后面的排序,这是放在parserHTML(url)中,来存放信息的。
Temp.append ({'city':city,'max_temp':int(max_temp)})
2.把爬取到的city和max_temp存放在里面,并对max_temp进行排序。
#按照从大到小的顺序对max_temp进行排序
Temp.sort(key=lambda x:x['max_temp'],reverse=True)
3.然后导入pyecharts库,以city为横轴,以温度为纵轴,建立一个直方图。这里我使用了map函数,对city和max_temp进行映射
#取出温度最高的前十城市
List = Temp[0:10]
#把城市名称取出来,以列表的形式返回。map函数会返回一个map对象。
cities = list(map(lambda x:x['city'] ,List))
#把温度信息取出来,以列表的形式返回。
temps = list(map(lambda x:x['min_temp'],List))
bar=Bar("中国最低气温排行榜")
bar.add('',cities,temps)
bar.render('temp.html')
这样就画出了一个简单的直方图,进行了一个简单的数据可视化。
在命令行中安装pyecharts:pip install pyecharts
pyecharts这个库很强大,我也只是做了一个简单的模仿。
这篇文章里面详细的介绍了pyecharts的用法:https://github.com/pyecharts/pyecharts
好了全部代码如下
import requests
from bs4 import BeautifulSoup
from pyecharts import Bar
Temp = []
def parserHTML(url):
headers = {
"User-Agent":"Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36"
}
r =requests.get(url,headers=headers)
r.encoding = r.apparent_encoding
html = r.text
soup=BeautifulSoup(html,'html5lib')
#定位到所有存放天气和城市信息大标签
conMidtab = soup.find('div',class_='conMidtab')
#定位到存放一个省份的天气信息的标签,还需要在每一个省份中找到每一个城市的信息。
tables = conMidtab.find_all('table')
for table in tables:
trs = table.find_all('tr')[2:]
for tr in trs:
tds = tr.find_all('td')
city_td = tds[-8]
city = list(city_td.stripped_strings)[0]
temp_td = tds[-5]
max_temp = list(temp_td.stripped_strings)[0]
Temp.append ({'city':city,'max_temp':int(max_temp)})
with open('temp.text','a',encoding='utf-8') as f:
f.write('{:^10}\t{:^4}\n'.format(city,max_temp,chr(12288)))
f.flush()
#print(city,min_temp)
def main():
print('{:^10}\t{:^4}'.format('城市','最高气温',chr(12288)))
urls=[
'http://www.weather.com.cn/textFC/hb.shtml',
'http://www.weather.com.cn/textFC/db.shtml',
'http://www.weather.com.cn/textFC/hd.shtml',
'http://www.weather.com.cn/textFC/hz.shtml',
'http://www.weather.com.cn/textFC/hn.shtml',
'http://www.weather.com.cn/textFC/xb.shtml',
'http://www.weather.com.cn/textFC/xn.shtml',
'http://www.weather.com.cn/textFC/gat.shtml'
]
for url in urls:
parserHTML(url)
Temp.sort(key=lambda x:x['max_temp'],reverse=True)
List = Temp[0:9]
#cities = []
#for city_temp in List:
#city = city_temp['city']
#cities.append(city)
cities= list(map(lambda x:x['city'],List))
temps = list(map(lambda x:x['max_temp'],List))
bar=Bar("中国最高气温排行榜")
bar.add('',cities,temps)
bar.render('temp.html')
if __name__=='__main__':
main()