上一次分享了使用 matplotlib 对爬取的豆瓣书籍排行榜进行分析, 但是发现 python 本身自带的这个绘图分析库还是有一些局限, 绘图不够美观等, 在网上搜索了一波, 发现现在有很多的支持 python 的绘图库可以使用, 本次尝试使用 pyecharts 对爬取的数据进行分析, 然后发现这个库实在是太好用了, 生成的库也很好看, 还能生成动态图, 简直是进行数据分析的一大神器!
pyecharts:pyecharts 是一个封装百度开源图表库 echarts 的包, 使用 pyecharts 可以生成独立的网页, 也可以在 flask,django 中集成使用.
本次爬取的首页地址是:
http://www.tianqihoubao.com/lishi/nanjing.html
爬取步骤:
爬取主网页, 获取进入每个南京市具体年份月份的天气数据的链接
爬取上方获取的具体链接的数据
存储数据
对数据进行筛选后使用 pyecharts 进行分析
话不多说, 马上开始吧!
步骤一
从上图可知, 我们需要先获取进入每个具体月份的链接, 才能爬取想要的数据, 所以首先定义获取具体链接的函数, 然后在爬取会方便很多; 查看网页源代码查找目标所在位置, 本次我依然是使用 lxml 库来进行数据的爬取 (PS: 感觉习惯了 lxml 其他库就不好用了), 这里需要注意的是, 我是将获得的结果一个一个的存入列表, 这种方法很笨, 但作为菜鸟的我确实不知道其他方法了, 还有就是发现爬取的部分链接缺了一点, 所以又定义了一个函数来补上.
- def get_mainurl(url): #定义获取月份天气的详细 url 函数
- res = requests.get(url, headers=headers)
- main_url = []
- if res.status_code == 200: #判断请求状态
- selector = etree.HTML(res.text)
- htmlurls = selector.xpath('//div[contains(@id,"content")]/div') #循环点
- try:
- for htmlurl in htmlurls:
- Jan = htmlurl.xpath('ul[1]/li[2]/a/@href')[0] #一月份天气 url
- main_url.append(Jan) #将网址放入列表中, 一个一个放是很蠢的方法, 但我也确实不知道其他方法了, 下同
- Feb = htmlurl.xpath('ul[1]/li[3]/a/@href')[0] #二月份天气 url
- main_url.append(Feb)
- Mar = htmlurl.xpath('ul[1]/li[4]/a/@href')[0] #同上, 下类推
- main_url.append(Mar)
- Apr = htmlurl.xpath('ul[2]/li[2]/a/@href')[0]
- main_url.append(Apr)
- May = htmlurl.xpath('ul[2]/li[3]/a/@href')[0]
- main_url.append(May)
- June = htmlurl.xpath('ul[2]/li[4]/a/@href')[0]
- main_url.append(June)
- July = htmlurl.xpath('ul[3]/li[2]/a/@href')[0]
- main_url.append(July)
- Aug = htmlurl.xpath('ul[3]/li[3]/a/@href')[0]
- main_url.append(Aug)
- Sep = htmlurl.xpath('ul[3]/li[4]/a/@href')[0]
- main_url.append(Sep)
- Oct = htmlurl.xpath('ul[4]/li[2]/a/@href')[0]
- main_url.append(Oct)
- Nov = htmlurl.xpath('ul[4]/li[3]/a/@href')[0]
- main_url.append(Nov)
- Dec = htmlurl.xpath('ul[4]/li[4]/a/@href')[0]
- main_url.append(Dec)
- time.sleep(0.5) #休眠 0.5s
- except IndexError:
- pass
- return main_url #将存了所有 url 的列表返回
- else:
- pass
- def link_url(url): #上面获取的 url 是不完整的, 此函数使其完整
- final_urls= []
- list_urls = get_mainurl(url)
- for list_url in list_urls:
- if len(list_url) < 30: #因为获取的 url 有一些少了'/lishi/', 所以需要判断一下
- list_url = 'http://www.tianqihoubao.com/lishi/' + list_url
- final_urls.append(list_url)
- else:
- list_url = 'http://www.tianqihoubao.com' + list_url
- final_urls.append(list_url)
- return final_urls
- def get_infos(detail_url): #爬取月份天气详细数据函数
- main_res = requests.get(detail_url, headers=headers)
- main_sele = etree.HTML(main_res.text)
- main_infos = main_sele.xpath('//div[@class="hd"]/div[1]/table/tr')
- i = True
- try:
- for info in main_infos:
- if i: #此处 i 的作用是跳过第一次循环, 因为第一个是非天气数据
- i = False
- continue
- else:
- date = info.xpath('td[1]/a/text()')[0].replace("\r\n", '').replace(' ','') #去掉换行符, 空格等, 下同
- weather = info.xpath('td[2]/text()')[0].replace("\r\n", '').replace(' ','')
- temps = info.xpath('td[3]/text()')[0].replace('\r\n', '').replace(' ','')
- clouds = info.xpath('td[4]/text()')[0].replace("\r\n", '').replace(' ','')
- with open('Nanjing.csv', 'a+', newline='', encoding='utf-8')as fp: #存入 CSV 文件
- writer = CSV.writer(fp)
- writer.writerow((date, weather, temps, clouds))
- except IndexError:
- pass
- import requests
- from lxml import etree
- import time
- import CSV
- from multiprocessing import Pool
- # 请求头
- 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'
- }
- if __name__ == '__main__': #执行主程序
- url = 'http://www.tianqihoubao.com/lishi/nanjing.html' #获取月份天气 url 的网址
- get_mainurl(url)
- details = link_url(url)
- with open('Nanjing.csv', 'a+', newline='', encoding='utf-8')as ff: #写入第一行作为表头
- writer = CSV.writer(ff)
- writer.writerow(('日期', '天气状况', '气温', '风力风向'))
- pool = Pool(processes=4) #使用多进程爬取
- pool.map(get_infos, details) #需要注意爬取结果并不是按顺序的, 可以用 Excel 进行排序
- import pandas as pd
- from pyecharts import Line, Pie, Page, Bar
- page = Page(page_title='南京气温分析') #page 使多个图位于一个网页, 网页名
- pd.set_option('display.max_rows', None) #设置使 dataframe 所有行都显示
- df = pd.read_csv('Nanjing.csv') #读取天气数据
- #获取最高气温
- Max_temps = []
- for max_data in df['气温']:
- Max_temps.append(int(max_data[0:2].replace('℃','')))
- Max_temps = Max_temps[:-109]
- #获取最低气温
- Low_temps = []
- for low_data in df['气温']:
- Low_temps.append(int(low_data[-3:-1].replace('/', '')))
- Low_temps = Low_temps[:-109]
- #获取 2011 年一月气温数据
- attr = ['{} 号'.format(str(i))for i in range(1,32)]
- Jan_Htemps = Max_temps[:31]
- Jan_Ltemps = Low_temps[:31]
- #绘制气温折线图
- line = Line('南京市 2011 年一月气温变化') #赋予将折线图对象, 命名
- line.add('当日最高气温', attr, Jan_Htemps, mark_point=['average', 'max', 'min'], #显示平均, 最大 / 小值
- mark_point_symbol='diamond', #特殊点用钻石形状显示
- mark_point_textcolor='red', #标注点颜色
- is_smooth=True #图像光滑
- )
- line.add('当日最低气温', attr, Jan_Ltemps, mark_point=['average', 'max', 'min'],
- mark_point_symbol='arrow',
- mark_point_textcolor='blue'
- )
- line.use_theme('dark') #背景颜色
- line.show_config() #调试输出 pyecharts 的 JS 配置信息
- page.add_chart(line) #添加到 page
- #统计 2011-2018 年的每天最高温的气温分布情况, 分四个阶梯
- Hzero_down = Hthrity_up = Hzup_fifdown = Hfifup_thrdown = 0
- for i in Max_temps:
- if i <= 0:
- Hzero_down += 1
- elif i<=15:
- Hzup_fifdown += 1
- elif i<=30:
- Hfifup_thrdown += 1
- else:
- Hthrity_up +=1
- #统计 2011-2018 年的每天最高温的气温分布情况分, 分四个阶层
- Lfiv_down = L25_up = Lfiv_tendown = Ltenup_25down = 0
- for i in Low_temps:
- if i <= -5:
- Lfiv_down += 1
- elif i<=10:
- Lfiv_tendown += 1
- elif i<=25:
- Ltenup_25down += 1
- else:
- L25_up +=1
- #绘图
- attr2 = ['0℃及以下', '0-15℃', '15-30℃', '30℃及以上'] #标签属性
- H_data = [Hzero_down, Hzup_fifdown, Hfifup_thrdown, Hthrity_up] #数据
- pie = Pie('南京市 2011 年 - 2018 年每日最高气温分布', title_pos='center', title_color='red') #绘制饼图, 标题位于中间, 标题颜色
- pie.add('',attr2, H_data, is_label_show=True, #展示标签
- legend_pos='right', legend_orient='vertical', #标签位置, 标签排列
- label_text_color=True, legend_text_color=True, #标签颜色
- )
- pie.show_config()
- page.add_chart(pie, name='饼图')
- #绘制环形图
- attr3 = ['-5℃及以下', '-5-10℃', '10-25℃', '25℃及以上']
- L_data = [Lfiv_down, Lfiv_tendown, Ltenup_25down, L25_up]
- pie2 = Pie('南京市 2011 年 - 2018 年每日最低气温分布', title_pos='center')
- pie2.add('',attr3, L_data, radius=[30, 70], is_label_show=True, #radius 环形图内外圆半径
- label_text_color=None, legend_orient='vertical',
- legend_pos='left', legend_text_color=None
- )
- pie2.show_config()
- page.add_chart(pie2, name='环形图')
- #绘制南京 2011-2018 年天气状况条形统计图
- Weather_NJ = []
- for Weathers in df['天气状况']:
- Weather_s = Weathers.split('/')
- Weather_NJ.append(Weather_s[0])
- Weather_NJ.append(Weather_s[1])
- Weather_NJ = Weather_NJ[:-218]
- sunny = rainy = yin_cloudy = lightening = duo_cloudy = snowy = 0
- for t in Weather_NJ:
- if t == '晴':
- sunny += 1
- elif t == '阴':
- yin_cloudy += 1
- elif t == '多云':
- duo_cloudy += 1
- elif t == '雷阵雨':
- lightening += 1
- elif '雨' in t and t != '雨夹雪':
- rainy += 1
- elif '雪' in t:
- snowy += 1
- else:
- pass
- Weather_attr = ['晴', '雨天', '多云', '阴天', '雷阵雨', '雪天']
- Weather_datas = [sunny, rainy, duo_cloudy, yin_cloudy, lightening, snowy]
- bar = Bar('南京市 2011-2018 年天气情况统计', '注意: 一天有两个天气变化, 部分日期天气情况可能丢失', title_pos='center')
- bar.add('天气状况', Weather_attr, Weather_datas, is_more_utils=True,
- mark_point=['max', 'min'], legend_pos='right'
- )
- bar.show_config()
- page.add_chart(bar)
- page.render('all_analysis.html') #网页地址
来源: https://www.cnblogs.com/berryguotoshare/p/10774173.html