推荐内容

python+pycharm+anaconda的安装

【python编程环境安装】全网最详细python环境安装。pycharm和anaconda手把手安装教学。_哔哩哔哩_bilibili

python:Download Python | Python.org

pycharm: PyCharm: the Python IDE for Professional Developers by JetBrains

anaconda: Anaconda | The World’s Most Popular Data Science Platform

如果觉得下载的太慢了

可以去这个网站找软件包:软件下载 | 我爱分享网 (zhanshaoyi.com)

(注意:解压密码:rjzkgzh

python的基础教程

【尚学堂.百战程序员】高淇 Python 400集 (完结) #新版_哔哩哔哩_bilibili

(注意:看完前100集就可以了

爬虫教学

爬虫是什么

网络爬虫也叫做网络机器人,可以代替人们自动地在互联网中进行数据信息的采集与整理。在大数据时代,信息的采集是一项重要的工作,如果单纯靠人力进行信息采集,不仅低效繁琐,搜集的成本也会提高。

此时,我们可以使用网络爬虫对数据信息进行自动采集,比如应用于搜索引擎中对站点进行爬取收录,应用于数据分析与挖掘中对数据进行采集,应用于金融分析中对金融数据进行采集,除此之外,还可以将网络爬虫应用于舆情监测与分析、目标客户数据的收集等各个领域。

​ ——知乎

爬虫的基本流程

1
2
3
4
5
6
7
8
# 使用软件
python >> 3.7.8
pycharm >> 2021.3

# python库
lxml == 4.6.2
requests == 2.26.0
pandas == 1.3.4

镜像源

豆瓣源: http://pypi.douban.com/simple/

清华源: https://pypi.tuna.tsinghua.edu.cn/simple

发起请求

通过Url向服务器发起request请求,请求可以包含额外的header信息。

1
2
3
4
5
6
7
import requests
url = 'http://tianqihoubao.com/'
header = {
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.55 Safari/537.36 Edg/96.0.1054.43'
}

response = requests.get(url, headers=header) # 发起请求

URL是什么:URL是web页的地址

header是什么:headers是解决requests请求反爬的方法之一,相当于我们进去这个网页的服务器本身,假装自己本身在爬取数据。对反爬虫网页,可以设置一些headers信息,模拟成浏览器取访问网站 。常用的header信息就是user-agenthost

怎么获取user-agent

在所要爬取的网页中,

​ 右键点击 >> 点击网络 >> 刷新网页 >> 随机选中一条信息 >> 查看标头 >> 下拉选择user-agent信息。

获取响应内容

如果服务器正常响应,那我们将会收到一个response,response即为我们所请求的网页内容,或许包含HTML,Json字符串或者二进制的数据(视频、图片)等。

1
print(response)

输出结果:

1
<Response [200]> # 200表示返回成功

Response的类型:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
'''
以下表示一类,并非一种。
1xx:信息性状态码
100: 继续(请求者应该继续提出请求。服务器已收到请求的一部分,正在等待其余部分)
101: 切换协议(请求者已要求服务器切换协议,服务器已确认并准备切换)

2xx:成功状态码
200: 成功(服务器已成功处理了请求)
201: 已创建(请求成功并且服务器创建了新的资源)
202: 已接受(服务器已接受请求,但尚未处理)
...

3xx:重定向状态码
300: 多种选择(针对请求,服务器可执行多种操作)
301: 永久移动(请求的网页已永久移动到新位置,即永久重定向)
302: 临时移动(请求的网页暂时跳转到其他页面,即暂时重定向)
...

4xx:客户端错误状态码
400: 错误请求(服务器无法解析该请求)
401: 未授权(请求没有进行身份验证或者验证未通过)
403: 禁止访问(服务器拒绝此请求)
...

5xx:服务器错误状态码
500: 内部服务器错误(服务器遇到错误,无法完成请求)
501: 未实现(服务器不具备完成请求的功能)
502: 错误网关(服务器作为网关或代理,从上游服务器收到无效响应)
...

'''

解析内容

在这里有人可能会使用正则表达式来提取内容,但是正则表达式会有不好的地方,正则表达式不容易写对,并且提取内容繁琐。(不过需要了解正则表达式的用法)

如果是HTML代码,则可以使用网页解析器进行解析;

1
2
3
from lxml import html # 新版本
from lxml import etree # 旧版本
# 这里面提供了xpath语法。

xpath的常用规则

表达式 描述
nodename 选取此节点的所有子节点
/ 从当前节点选取直接子节点
// 从当前节点选取子孙节点
. 选取当前节点
选取当前节点的父节点
@ 选取属性

一个基本网页

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<title>html演示</title>
</head>

<body>
<div class="so_0">
<ul>
<li class="item_0">这是第一个li</li>
<li class="item_1">这是第二个li</li>
</ul>
</div>

<div id="id_from_0" class="so_2">
<ul>
<a href="http://www.baidu.com/">百度搜索</a>
<a href="https://www.google.com.hk/">Google搜索</a>
<a href="https://cn.bing.com/?mkt=zh-CN">Bing搜索</a>
</ul>
<ul>
<a href="https://xueshu.baidu.com/">百度学术</a>
</ul>
<ul>
<a href="https://fanyi.baidu.com/">百度翻译</a>
</ul>
</div>
</body>

</html>

网页源代码是一个树的分布,每一个标签都是一个树杈。

如何使用xpath定位标签

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
定位到:标题
方法一(全路径)
title = html/head/title/text()
方法二(相对路径)
title = //title/text()

定位到:“这是第一个li”
方法一(全路径)
li_first = html/body/div[1]/ul/li[1]/text()
方法二(相对路径)
li_fisrt = //div[@class="so_0"]/ul/li[1]/text()

定位到:搜索引擎
方法一(全路径)
search_engine = html/body/div[2]/ul[1]/a/text()
方法二(相对路径)
search_engine = //div[@class="so_2"]/ul[1]/a/text()
# class不一定是唯一值,class相当于人名
或者
search_engine = //div[@id="id_from_0"]/ul[1]/a/text()
# id必定是唯一值,相当于身份证号(优先选择)

定位到:搜索引擎的网址
方法一(全路径)
search_engine_url = html/body/div[1]/ul[1]/a/@href
方法二(相对路径)
search_engine_url = //div[@class="so_2"]/ul[1]/a/@href
或者
search_engine_url = //div[@id="id_from_0"]/ul[1]/a/@href

复习xpath的常用规则

表达式 描述
nodename 选取此节点的所有子节点
/ 从当前节点选取直接子节点
// 从当前节点选取子孙节点
. 选取当前节点
选取当前节点的父节点
@ 选取属性

lxml代码写法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# html_text就是上面的html转化成文本类型
# 把网页按照html格式自动补全
content = html.etree.HTML(html_text)

# 输出补全后的html
html_pri = html.etree.tostring(content, encoding='utf-8').decode('utf-8')

# 定位到:标题
head_title = content.xpath('//title/text()')

# 定位到:“这是第一个li”
li_first = content.xpath('//div[@class="so_0"]/ul/li[1]/text()')

# 定位到:搜索引擎
search_engine = content.xpath('//div[@id="id_from_0"]/ul[1]/a/text()')

# 定位到:搜索引擎的网址
search_engine_url = content.xpath('//div[@id="id_from_0"]/ul[1]/a/@href')

## 注意:xpath提取出来的是列表

xpath helper的安装

以Edge浏览器作为示例。

xpath helper的使用

以滁州市天气情况为例

1
url = http://tianqihoubao.com/weather/top/chuzhou.html
1
2
3
4
5
6
7
8
# 锁定日期
date = '//div[@id="content"]//tbody/tr/td[2]/b/a/text()'

# 锁定日期的url
date_url = '//div[@id="content"]//tbody/tr/td[2]/b/a/@href'

# 提取白天的天气情况
day_weather = '//div[@id="content"]//tbody/tr/td[3]/text()'

实战:爬取滁州市某月的天气情况

过去30天的数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
import requests
from lxml import etree
import pandas as pd


city_url = 'http://tianqihoubao.com/weather/top/chuzhou.html'
respon = requests.get(city_url).text
content_text = etree.HTML(respon)

date_list = []
day_weather_list = []
day_wind_list = []
day_T_list = []
night_weather_list = []
night_wind_list = []
night_T_list = []

tr_list = content_text.xpath('//div[@id="content"]//table//tr')
for tr in tr_list[2:-1]:
date = tr.xpath('./td[2]/b/a/text()')[0]
day_weather = tr.xpath('./td[3]/text()')[0].strip()
day_wind = tr.xpath('./td[4]/text()')[0]
day_T = tr.xpath('./td[5]/text()')[0]
night_weather = tr.xpath('./td[6]/text()')[0].strip()
night_wind = tr.xpath('./td[7]/text()')[0].strip()
night_T = tr.xpath('./td[8]/text()')[0].strip()
date_list.append(date)
day_weather_list.append(day_weather)
day_wind_list.append(day_wind)
day_T_list.append(day_T)
night_weather_list.append(night_weather)
night_wind_list.append(night_wind)
night_T_list.append(night_T)

# 保存数据
df = pd.DataFrame({
'日期': date_list,
'白天天气': day_weather_list,
'白天风力风向': day_wind_list,
'白天最高气温': day_T_list,
'夜间天气': night_weather_list,
'夜间风力风向': night_wind_list,
'夜间最高气温': night_T_list
})
df.to_excel('滁州市天气情况.xlsx', index=False)

指定城市的历史天气数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
import requests
from lxml import etree
import pandas as pd
from xpinyin import Pinyin # xpinyin库是把汉字转化成拼音


name_city = '张家口' # 这里输入指定城市
P = Pinyin()
name_city_pinyin = P.get_pinyin(name_city, '')
header = {
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.45 Safari/537.36 Edg/96.0.1054.29'
}
urls_api = []
urls_month = []
for i in range(2014, 2022):
yue_list = ['01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '11', '12']
for j in yue_list:
date_url = str(i)+str(j)
url_api = 'http://www.tianqihoubao.com/aqi/{0}-{1}.html'.format(name_city_pinyin, date_url)
url_month = 'http://www.tianqihoubao.com/lishi/{0}/month/{1}.html'.format(name_city_pinyin, date_url)
urls_api.append(url_api)
urls_month.append(url_month)


date_api_list = []
AQI_list = []
grade_list = []
PM25_list = []
PM10_list = []
SO2_list = []
NO2_list = []
CO_list = []
O3_list = []

date_month_list = []
weather_day_list = []
Tem_day_list = []
wind_day_list = []
weather_night_list = []
Tem_night_list = []
wind_night_list = []

for url_api in urls_api:
content_api = requests.get(url_api, headers=header).text
html_api = etree.HTML(content_api)
days_data = html_api.xpath('//div[@class="api_month_list"]//tr')
for day_data in days_data[1:-1]:
date = day_data.xpath('./td[1]/text()')[0].split()[0]
AQI = day_data.xpath('./td[2]/text()')[0].split()[0]
grade = day_data.xpath('./td[3]/text()')[0].split()[0]
PM25 = day_data.xpath('./td[5]/text()')[0]
PM10 = day_data.xpath('./td[6]/text()')[0]
SO2 = day_data.xpath('./td[7]/text()')[0]
NO2 = day_data.xpath('./td[8]/text()')[0]
CO = day_data.xpath('./td[9]/text()')[0]
O3 = day_data.xpath('./td[10]/text()')[0]
date_api_list.append(date)
AQI_list.append(AQI)
grade_list.append(grade)
PM25_list.append(PM25)
PM10_list.append(PM10)
SO2_list.append(SO2)
NO2_list.append(NO2)
CO_list.append(CO)
O3_list.append(O3)

for url_month in urls_month[1:-1]:
content_month = requests.get(url_month, headers=header).text
html_month = etree.HTML(content_month)
days_data_ = html_month.xpath('//div[@id="content"]//tr')
for day_data_ in days_data_[1:-1]:
date_month = day_data_.xpath('./td[1]/a/text()')[0].split()[0].replace('年', '-').replace('月', '-').replace('日', '')
weather_day = day_data_.xpath('./td[2]/text()')[0].split('/')[0].split()[0]
weather_night = day_data_.xpath('./td[2]/text()')[0].split('/')[1].split()[0]
Tem_day = day_data_.xpath('./td[3]/text()')[0].split('/')[0].split()[0]
Tem_night = day_data_.xpath('./td[3]/text()')[0].split('/')[1].split()[0]
wind_day = day_data_.xpath('./td[4]/text()')[0].split('/')[0].replace('\r', '').replace('\n', '').strip()
wind_night = day_data_.xpath('./td[4]/text()')[0].split('/')[1].replace('\r', '').replace('\n', '').strip()
date_month_list.append(date_month)
weather_day_list.append(weather_day)
weather_night_list.append(weather_night)
Tem_day_list.append(Tem_day)
Tem_night_list.append(Tem_night)
wind_day_list.append(wind_day)
wind_night_list.append(wind_night)

# 数据储存
df1 = pd.DataFrame(
{
'空气质量日期': date_api_list,
'AQI': AQI_list,
'质量等级': grade_list,
'PM2.5': PM25_list,
'PM10': PM10_list,
'SO2': SO2_list,
'NO2': NO2_list,
'CO': CO_list,
'O3': O3_list,
}
)

df2 = pd.DataFrame(
{
'历史天气日期': date_month_list,
'白日天气情况': weather_day_list,
'夜晚天气情况': weather_night_list,
'白日气温': Tem_day_list,
'夜晚气温': Tem_night_list,
'白日风力风向': wind_day_list,
'夜晚风力风向': wind_night_list
}
)

# 合并数据
df1['空气质量日期'] = pd.to_datetime(df1['空气质量日期'])
df2['历史天气日期'] = pd.to_datetime(df2['历史天气日期'])
df1_df2 = df1.merge(df2, left_on='空气质量日期', right_on='历史天气日期')
df1_df2 = df1_df2.drop('历史天气日期', axis=1)

df1.to_excel('{0}空气质量.xlsx'.format(name_city), index=False)
df2.to_excel('{0}历史天气.xlsx'.format(name_city), index=False)
df1_df2.to_excel('{0}数据合并.xlsx'.format(name_city), index=False)

保存数据

可以保存到本地文件,也可以保存到数据库(MySQL,Redis,Mongodb等)