用python对页面进行爬取
例 1
以下是一个简单的python爬取demo,将url中的内容存储到bridge.png中:
import requests
import json
if __name__ == '__main__':
url = 'https://t7.baidu.com/it/u=1595072465,3644073269&fm=193&f=GIF'
req = requests.get(url)
f = open('bridge.png', 'wb')
f.write(req.content)
f.close()
例 2
下面我们爬取以下更复杂一些的数据:
import requests
import json
import numpy as np
import pandas as pd
if __name__ == '__main__':
url_someStock = 'https://q.stock.sohu.com/hisHq?code=cn_300985&start=20210429&end=20210813&stat=1&order=D&period=d&callback=historySearchHandler&rt=jsonp&r=0.669360311489062&0.925820289825436'
response = requests.get(url_someStock)
data = response.text
start = data.find('{')
end = data.find('}')
data = data[start:end+1]
url_someStock里面,即我们的数据,这是一个关于股票某短时间内的历史行情的数据,我们通过requests读取这组数据后,找到两个大括号,中间的内容,就是我们一行json格式数据的内容。
数据的json格式如下图,一组数据包括日期、开盘、收盘、涨跌额、涨跌幅、最低、最高、成交量(手)、成交金额(万)、换手率、盘后量(手):
data = json.loads(data)
data = data['hq']
data = np.array(data)
np.set_printoptions(linewidth=500)
data = data[:, [0,1,2,5,6,7,8]]
print(data)
使用json.loads()函数,将json格式数据转换为字典,而data[‘hq’]中的内容就是我们需要的具体行情信息,是一个list格式。将这个list转化为一个numpy.array便于后续操作。
第4行的意思是在输出时一行允许输出内容上限为500个字符(因为数据较长,一组数据超过了默认的80个字符)。
第5行的冒号的意思是输出array中的每一行数据,冒号后面的[0,1,2,5,6,7,8]表示输出第0,1,2,5,6,7,8列数据,输出格式如下图(如果没有第4行,则每行数据会从中间换行):
data = pd.DataFrame(data, columns=['日期', '开盘', '收盘', '最低', '最高', '成交量(手)', '成交金额(万)'])
data.sort_values(by=['日期'], inplace=True, ascending=True)
data.set_index(keys=['日期'], inplace=True)
data.to_excel('stock300985.xlsx')
通过pandas将刚才的数据转换成一个DataFrame格式,并以日期为索引:
这里的inplace=True的意思是在原数据上进行排序,inplace的默认值是False,使用方式是:
t = data.set_index()
这样的话t里面就是排列后的结果,而data里数据不变。
例 3
第三个例子我们来尝试爬取一下新冠疫情的全球数据。
首先我们从这个网站爬取。
在页面任意位置右键点击检查,点击Networks后刷新页面,即可获取页面网络数据:
在右侧列表中找有可能的数据,一般看看文件名和文件格式就可以确定了。点击数据后,可以点击Response查看具体数据内容,然后复制Headers中的网址,这个网址就是我们需要的数据了。
数据格式如下:
我们需要的数据是areaTree里的全球数据。获取代码如下:
import json
import requests
import pandas as pd
if __name__ == '__main__':
headers = {
'user-agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.149 Safari/537.36'
}
url = 'https://c.m.163.com/ug/api/wuhan/app/data/list-total?t=325820807889'
r = requests.get(url, headers=headers)
data_json = json.loads(r.text)
data = data_json['data']
areaTree = data['areaTree']
获取数据后,我们需要摘取其中用的到的数据存储下来,获取数据的函数get_data如下,这个函数的输入为刚才的areaTree和我们需要的数据名称形成的list,并且获取数据中today标签下的数据(第2行),将数据列命名修改为“today_+原命名”(第3行),info中存储了info_list里我们需要的内容(第8行):
def get_data(data, info_list):
today_data = pd.DataFrame([d['today'] for d in data])
today_data.columns = ['today_' + i for i in today_data.columns]
total_data = pd.DataFrame([d['total'] for d in data])
total_data.columns = ['total_' + i for i in total_data.columns]
info = pd.DataFrame(data)[info_list] # 主要信息
return pd.concat([info, total_data, today_data], axis=1) # 按照列合并
获取数据后,我们使用函数save_data,存储数据,函数如下:
def save_data(data, name):
file_name = name + '_' + time.strftime('%Y_%m_%d', time.localtime(time.time())) + '.csv'
data.to_csv(file_name, index=None, encoding='utf_8_sig')
print(file_name + ' 保存成功!')
在主函数中调用这两个函数:
today_world = get_data(areaTree, ['id', 'lastUpdateTime', 'name'])
save_data(today_world, 'today_world')
一些附加内容
刚才我们已经获得了数据today_world_2021_08_16.csv,现在输入以下代码:
import pandas as pd
if __name__ == '__main__':
pd.set_option('display.min_rows', 10)
pd.set_option('display.width', 1000)
pd.set_option('display.max_columns', 20)
data = pd.read_csv("today_world_2021_08_16.csv")
print(data['name', 'total_confirm'])
结果会报错,最后一行的写法是错误的,我的原意是输出“name”和“total_confirm”两列的内容,但是最后一行的写法,python会认为我要找一行名为“‘name’, ‘total_confirm’”的数据。正确写法应该是:
print(data[['name', 'total_confirm']])
还可以做以下的打印操作:
print(data.head(10)) # 获取前10
print(data.tail(10)) # 获取后10个
print(data.sample(10)) # 随机获取10个
print(data.iloc[2:5, 4:9]) # 获取第2行到第5行,第4列到第9列内容
print(data.iloc[:5, 'name']) # 获取前5行,列名为name的内容
可视化
现在我们来做一个可视化的疫情图表:
import matplotlib.pyplot as plt
import matplotlib as mpl
data.sort_values(by='total_confirm', inplace=True, ascending=False)
d = data[['name', 'total_confirm']]
d = d.iloc[:10, :]
mpl.rcParams['font.sans-serif'] = ['fangsong']
mpl.rcParams['axes.unicode_minus'] = False
plt.figure(figsize=(8, 6))
plt.bar(d['name'], d['total_confirm'], width=0.75, color='y')
plt.xlabel('国家')
plt.ylabel('确诊人数', fontsize=15)
plt.title('新冠确诊数量前十国家', fontsize=20)
plt.show()
效果如图:
zip函数
zip函数的作用是把两组数据一一对应的关联起来,输入以下代码:
name = 'n1', 'n2', 'n3', 'n4', 'n5'
num = [100, 0], [200, 20], [123, 345], [222, 43], [12, 56]
print(list(zip(name, num)))
print(dict(zip(name, num)))
print(pd.DataFrame(dict(zip(name, num))))
输出结果:
今天大概就讲到这里,后面有时间的话在尝试用beautiful soup获取标准化数据进行爬取。