爬取2018年8月27日~9月2日的欧元汇率。
先说结论:
如果是现汇卖出价,可以选择
2018-08-31 09:19:26 ,现钞卖出价 805.28。
我刚问了报销过的人她说任选都行,可以不是中行折算价。
最近出差,学校可以以人民币的形式报销路费、住宿费,汇率,可以任选出差期间的任何一天任何时候的中国银行的汇率,中国银行网站上的汇率长这样:
如果想要合理利用规则,多回一点本,不妨选择汇率最坑的一天(默默给财务处大佬作揖,别搞我,我为北邮体育馆平均每周至少贡献20元)
50多页汇率都让我用小本本记上吗?
比较笨的方法
在页面中必须要选择这个东西,我去,日期怎么点?
还算可以的方法
这里面要稍微琢磨一下的一点,是如果你仅仅输入了网址的内容,返回的是这个空空的页面“对不起,检索词不能为空”,这时候应该怎么办?
回到最初的网页,打开控制台,选中network,刷新页面看一下,果然是你,表单就在这里:
那么我直接在post请求里面加上headers和表单就可以了。
import requests
url = 'http://srh.bankofchina.com/search/whpj/search.jsp'
headers = {
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8',
'Accept-Encoding': 'gzip, deflate',
'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8',
'Cache-Control': 'max-age=0',
'Connection': 'keep-alive',
'Content-Length': '58',
'Content-Type': 'application/x-www-form-urlencoded',
'Cookie': 'JSESSIONID=0000eiLWbmpU1jmVd-YyiUf_XDM:-1',
'Host': 'srh.bankofchina.com',
'Origin': 'http://srh.bankofchina.com',
'Referer': 'http://srh.bankofchina.com/search/whpj/search.jsp',
'Upgrade-Insecure-Requests': '1',
'User-Agent':'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36'
}
form_data = {
'erectDate': '2018-08-26', #起始日期
'nothing': '2018-09-02', #截止日期
'pjname': '1326', #1326是欧元的代码
'page': '1' #打开第一页
}
wb_data = requests.post(url,headers = headers,data=form_data)
print(wb_data.text)
爬取结果:
中国银行外汇牌价
当前位置:首页>外汇牌价
货币名称
现汇买入价
现钞买入价
现汇卖出价
现钞卖出价
中行折算价
发布时间
欧元
790.41
765.85
796.24
797.82
796.46
2018.09.02 05:30:00
欧元
790.41
765.85
796.24
797.82
796.46
2018.09.02 05:30:00
欧元
790.41
765.85
796.24
797.82
796.46
2018.09.02 05:30:00
欧元
790.41
765.85
796.24
797.82
796.46
2018.09.02 05:30:00
欧元
790.41
765.85
796.24
797.82
796.46
2018.09.02 05:30:00
欧元
790.41
765.85
796.24
797.82
796.46
2018.09.01 05:30:00
欧元
790.41
765.85
796.24
797.82
796.46
2018.09.01 05:30:00
欧元
790.41
765.85
796.24
797.82
796.46
2018.09.02 00:00:05
欧元
790.41
765.85
796.24
797.82
796.46
2018.09.01 05:30:00
欧元
790.41
765.85
796.24
797.82
796.46
2018.09.01 05:30:00
欧元
790.41
765.85
796.24
797.82
796.46
2018.09.01 05:30:00
欧元
790.41
765.85
796.24
797.82
796.46
2018.09.01 04:52:28
欧元
789.45
764.92
795.27
796.86
796.46
2018.09.01 00:11:15
欧元
789.52
764.99
795.34
796.93
796.46
2018.09.01 00:00:13
欧元
790
765.45
795.83
797.41
796.46
2018.09.01 00:00:05
欧元
790
765.45
795.83
797.41
796.46
2018.08.31 23:52:31
欧元
790
765.45
795.83
797.41
796.46
2018.08.31 23:52:31
欧元
790
765.45
795.83
797.41
796.46
2018.08.31 23:52:31
欧元
790.64
766.07
796.47
798.05
796.46
2018.08.31 23:22:05
欧元
790.8
766.23
796.63
798.22
796.46
2018.08.31 23:18:43
这个一整好像挺麻烦的,有没有更简单的方法呢?有!
表格信息原本是长这样的:
点击查看源(view source)
,可以切换成钩子形式,得来全不费功夫
早知如此何必费那个劲呢?(早知道就不那么搞)
我直接打开这个网页好不好?好的!毫无差别。
import requests
url = 'http://srh.bankofchina.com/search/whpj/search.jsp?erectDate=2018-08-26¬hing=2018-09-02&pjname=1326&page=1'
wb_data = requests.get(url)
print(wb_data.text)
效果一样的。
网页的解析
这里是带有tbody的,但是如果真的用beautifulsoup解析会发现tbody是不存在的,导致body > div > div.BOC_main.publish > table > tbody > tr > td
选择出来的结果为空列表,这是一个已知问题,解析网页的时候,会遇到tbody标签。tbody标签有的时候可以解析,有的时候不可以解析,遇到tbody标签时要看网页源代码,如果源代码有tbody标签,就要加上tbody标签才能解析。
如果源代码没有tbody标签,那么tbody标签是浏览器对html文本进行一定的规范化而强行加上去的,这时如果有tbody则无法解析出来,此时去掉其中的tbody即可。
MacOS环境下的Python3.6代码
from bs4 import BeautifulSoup
import pandas as pd
import requests
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.font_manager import FontProperties
# 解决matplotlib中文显示问题,仅适用windows系统
plt.rcParams['font.sans-serif'] = ['SimHei']
# 解决matplotlib中文显示问题,仅适用mac系统
def get_chinese_font():
return FontProperties(fname='/System/Library/Fonts/PingFang.ttc')
url = 'http://srh.bankofchina.com/search/whpj/search.jsp?erectDate=2018-08-27¬hing=2018-09-02&pjname=1326&page=1'
wb_data = requests.get(url)
#print(wb_data.text)
soup= BeautifulSoup(wb_data.text,'lxml')
raw_price_tag = soup.select('body > div > div.BOC_main.publish > table > tr > th')
raw_price = soup.select('body > div > div.BOC_main.publish > table > tr > td')[:-1]
#body > div > div.BOC_main.publish > table > tbody > tr:nth-child(2) > td:nth-child(1)
#print(raw_price.json())
price_dict = {}
raw_price = [i.text for i in raw_price]
for i in range(len(raw_price_tag)):
price_dict[raw_price_tag[i].text] = raw_price[i::len(raw_price_tag)]
urls = [url[:-1]+str(i) for i in range(2,52)] #一共51页
for each_url in urls:
wb_data = requests.get(each_url)
soup = BeautifulSoup(wb_data.text, 'lxml')
raw_price = soup.select('body > div > div.BOC_main.publish > table > tr > td')[:-1]
raw_price = [i.text for i in raw_price]
for i in range(len(raw_price_tag)):
price_dict[raw_price_tag[i].text] += raw_price[i::len(raw_price_tag)]
df = pd.DataFrame(price_dict).drop_duplicates() #成帧、去重
df['发布时间'] = pd.to_datetime(df['发布时间'])
df['具体时间'] = df['发布时间'].dt.strftime('%H:%M:%S') #时间时分秒的提取
df.set_index("发布时间", inplace=True)
#print(df.sort_values(by = ['发布时间','中行折算价'],ascending=[True,False])) #每天里面最高到最低
#print(df['2018-09-02']) 可以按照日期过滤
print('每日最坑价和最坑时间如下:')
tag_list = ['现汇买入价', '现钞买入价', '现汇卖出价', '现钞卖出价', '中行折算价']
days = ['2018-08-27','2018-08-28','2018-08-29','2018-08-30','2018-08-31','2018-09-01','2018-09-02']
rsp_df = df.resample('D').max() #仅仅针对时间序列的操作 每一项的最大值
df_extra=pd.DataFrame(np.arange(42).reshape((7,6)),index=days,columns=['现汇买入价', '现钞买入价', '现汇卖出价', '现钞卖出价', '中行折算价','具体时间'])
for i in range(rsp_df.shape[0]):
this_day = days[i]
max_price = max(rsp_df.iloc[i][tag_list].values)
max__price_loc = tag_list[list(rsp_df.iloc[i][tag_list].values).index(max_price)]
this_day_df = df[this_day]
high_frame = this_day_df[this_day_df[max__price_loc]==max_price].iloc[0]
high_day = str(high_frame.name)[:10]
high_time = high_frame["具体时间"]
df_extra.iloc[i] = high_frame
print(f'{high_day} {high_time} 此时{max__price_loc}:{max_price}')
if i == 0:
best_price = max_price
elif max_price > best_price:
best_day,best_time ,best_tag, best_price= high_day,high_time,max__price_loc,max_price
print('-----------------------------------')
print('日最高价全帧预览:')
print(df_extra)
print('-----------------------------------')
print(f'综上所述,欧元对人民币汇率最高的时机:\n{best_day} {best_time} 此时{best_tag}:{best_price}')
print('-----------------------------------')
#绘图之前进行强制类型转换保证数据可绘
for each_tag in tag_list:
rsp_df[each_tag] = rsp_df[each_tag].astype(float)
df_for_plot = rsp_df.drop(['货币名称'],axis = 1) #去掉不能画图的货币名称
df_for_plot = rsp_df.drop(['具体时间'],axis = 1) #去掉不能画图的具体时间
df_for_plot.plot()
plt.title('2018年八月末九月初 中行 欧元对人民币汇率变化', fontproperties=get_chinese_font())
plt.legend(loc='best', prop=get_chinese_font())
#plt.interactive(False)
plt.ylabel('人民币/100欧', #y标签
fontproperties = get_chinese_font(), #字体
fontsize=14 #字大小
)
plt.xlabel('日期', #y标签
fontproperties = get_chinese_font(), #字体
fontsize=14 #字大小
)
plt.tight_layout()
plt.savefig('./cur.png')
plt.show()
每日最坑价和最坑时间如下:
2018-08-27 23:03:27 此时现钞卖出价:800.9
2018-08-28 21:29:12 此时现钞卖出价:802.52
2018-08-29 22:17:07 此时现钞卖出价:803.62
2018-08-30 15:23:29 此时现钞卖出价:805.27
2018-08-31 09:19:26 此时现钞卖出价:805.28
2018-09-01 05:30:00 此时现钞卖出价:797.82
2018-09-02 05:30:00 此时现钞卖出价:797.82
-----------------------------------
日最高价全帧预览:
现汇买入价 现钞买入价 现汇卖出价 现钞卖出价 中行折算价 具体时间
2018-08-27 793.46 768.8 799.31 800.9 797.77 23:03:27
2018-08-28 795.06 770.36 800.93 802.52 795.45 21:29:12
2018-08-29 796.15 771.41 802.02 803.62 795.9 22:17:07
2018-08-30 797.78 773 803.67 805.27 797.59 15:23:29
2018-08-31 797.79 773.01 803.68 805.28 797.59 09:19:26
2018-09-01 790.41 765.85 796.24 797.82 796.46 05:30:00
2018-09-02 790.41 765.85 796.24 797.82 796.46 05:30:00
-----------------------------------
综上所述,欧元对人民币汇率最高的时机:
2018-08-31 09:19:26 此时现钞卖出价:805.28
坑
- 坑1
tbody问题 - 坑2
pandas帧内的对象在为object类型时能进行比较,但是不能画图,要转.astype(float)
。 - 坑3
时间序列的日期提取
df['具体时间'] = df['发布时间'].dt.strftime('%H:%M:%S') #时间时分秒的提取
后记
不要学我刷中行的网站,我的ip已经被中行block了,这篇结果我是开手机热点爬的(捂脸)。