美文网首页
09 使用Python爬取中国银行网站选择汇率最坑的一天

09 使用Python爬取中国银行网站选择汇率最坑的一天

作者: 夏威夷的芒果 | 来源:发表于2018-09-06 18:45 被阅读367次

爬取2018年8月27日~9月2日的欧元汇率。
先说结论:
如果是现汇卖出价,可以选择
2018-08-31 09:19:26 ,现钞卖出价 805.28。
我刚问了报销过的人她说任选都行,可以不是中行折算价。

最近出差,学校可以以人民币的形式报销路费、住宿费,汇率,可以任选出差期间的任何一天任何时候的中国银行的汇率,中国银行网站上的汇率长这样:


如果想要合理利用规则,多回一点本,不妨选择汇率最坑的一天(默默给财务处大佬作揖,别搞我,我为北邮体育馆平均每周至少贡献20元)

50多页汇率都让我用小本本记上吗?


50多页汇率都让我用小本本记上吗?

比较笨的方法

在页面中必须要选择这个东西,我去,日期怎么点?

selenium模拟点击,但是这也太笨重了,都犯不上,万一是js对象,还不知道能不能获取过来。

还算可以的方法

这里面要稍微琢磨一下的一点,是如果你仅仅输入了网址的内容,返回的是这个空空的页面“对不起,检索词不能为空”,这时候应该怎么办?


回到最初的网页,打开控制台,选中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)

爬取结果:

    <html>
    <head>
    <META content="IE=7.0000" http-equiv="X-UA-Compatible">
    <meta http-equiv="Content-Type" content="text/html; charset=GBK">
    <title>中国银行外汇牌价</title>
    <SCRIPT LANGUAGE="JavaScript" src="../js/wcm_page_2013.js"></SCRIPT>
    <script type="text/javascript" src="../js/My97DatePicker/WdatePicker.js"></script>
    </head>
    
    
<body onload="init_list();" style='width:980px;margin:0 auto;'>
<!-- 头部嵌套 -->
<link href="http://www.bankofchina.com/images/boc2013_reset.css" rel="stylesheet" type="text/css" ignoreapd="1">
<link href="http://www.bankofchina.com/images/boc2013_common.css" rel="stylesheet" type="text/css" ignoreapd="1">
<link href="http://www.bankofchina.com/images/boc2013_pages.css" rel="stylesheet" type="text/css" ignoreapd="1">
<!--[if lte IE 8]>
<link type="text/css" rel="stylesheet" href="http://www.bankofchina.com/images/boc2013_iestyle.css">
<![endif]-->
<script language="JavaScript" src="http://www.bankofchina.com/head.js" ignoreapd="1"></script>
<script type="text/javascript" src="http://www.bankofchina.com/images/boc2013_jquery-min.js" ignoreapd="1"></script>
<script type="text/javascript" src="http://www.bankofchina.com/images/boc2013_boc.js" ignoreapd="1"></script>
<style type="text/css">
body{
    background:#FFF;
    font: 12px/26px Verdana,Geneva,sans-serif,"宋体";
    color: rgb(83, 83, 83);
    margin:0 auto;
    text-align:center;
}
.wrapper{text-align:left;}
.invest_t table td,.publish table th ,.publish table tr{
    font-size:12px;
}
.invest_t table tr td select{
    height:30px;
}
.invest_t table tr th select{
    height:auto;
}
.invest_t select{
    width:auto;
    height:auto;
}
#calendarTable tr td{
    height:20px;
}
</style>
<div class="wrapper">
<script language="JavaScript">
    <!--
    createTop();
    //-->
</script>
<!-- 页面导航 -->
<div class='cramb' id='PL_NAVIGATOR'><span>当前位置:</span><a href="http://www.bankofchina.com">首页</a>>外汇牌价</div>
<h2 class="title">&nbsp;<br><br></h2>
<form method="post" name="historysearchform" id="historysearchform" action="search.jsp">
<div class="invest_t" style="float:left;width:980px;">
<SCRIPT language=javascript src="../js/WebCalendar.js"></SCRIPT> 
    <table cellpadding="0" cellspacing="0" width="100%">
        <tr>
            <td align="right" width="8%">起始时间:</td>
            <td align="left" width="110px;">
                <div class="search_bar" style="float:left;width:100px;margin-left:10px;">
                    <input class="search_ipt" style="width:100px;" type="text" name="erectDate" value="2018-08-26"  onclick="new Calendar(null, null,0).show(this);" readonly>
                </div>
            </td>
            <td align="right" width="8%">结束时间:</td>
            <td align="left" width="110px;">
                <div class="search_bar" style="float:left;width:100px;margin-left:10px;">
                    <input class="search_ipt" style="width:100px;" type="text" name="nothing" value="2018-09-02"  onclick="new Calendar(null, null,0).show(this);" readonly>
                </div>
            </td>
            <td align="right" width="10%">牌价选择:</td>
            <td align="left" width="110px;">
                
                <select name="pjname" id="pjname">
                    <option value="0" >选择货币</option>
                    <option value="1314" >英镑</option>
                    <option value="1315" >港币</option>
                    <option value="1316" >美元</option>
                    <option value="1317" >瑞士法郎</option>
                    <option value="1318" >德国马克</option>
                    <option value="1319" >法国法郎</option>
                    <option value="1375" >新加坡元</option>
                    <option value="1320" >瑞典克朗</option>
                    <option value="1321" >丹麦克朗</option>
                    <option value="1322" >挪威克朗</option>
                    <option value="1323" >日元</option>
                    <option value="1324" >加拿大元</option>
                    <option value="1325" >澳大利亚元</option>
                    <option value="1326"  selected>欧元</option>
                    <option value="1327" >澳门元</option>
                    <option value="1328" >菲律宾比索</option>
                    <option value="1329" >泰国铢</option>
                    <option value="1330" >新西兰元</option>
                    <option value="1331" >韩元</option>
                    <option value="1843" >卢布</option>
                    <option value="2890" >林吉特</option>
                    <option value="2895" >新台币</option>
                    <option value="1370" >西班牙比塞塔</option>
                    <option value="1371" >意大利里拉</option>
                    <option value="1372" >荷兰盾</option>
                    <option value="1373" >比利时法郎</option>
                    <option value="1374" >芬兰马克</option>
                    <option value="3030" >印尼卢比</option>
                    <option value="3253" >巴西里亚尔</option>
                    <option value="3899" >阿联酋迪拉姆</option>
                    <option value="3900" >印度卢比</option>
                    <option value="3901" >南非兰特</option>
                    <option value="4418" >沙特里亚尔</option>
                    <option value="4560" >土耳其里拉</option>
                </select>
            </td>
            <td width="30px;" align="left">
                <input class="search_btn" style="float:right;margin-righth:26px;" type="button" onclick="executeSearch()">
            </td>
            <td>&nbsp;</td>
        </tr>
    </table>
</div>
</form>

<div class="BOC_main publish">
    <table cellpadding="0" cellspacing="0" width="100%" align="left">
    <tr>
        <th>货币名称</th>
        <th>现汇买入价</th>
        <th>现钞买入价</th>
        <th>现汇卖出价</th>
        <th>现钞卖出价</th>
        <th>中行折算价</th>
        <th>发布时间</th>
    </tr>
 
        <tr>
            <td>欧元</td>
            <td>790.41</td>
                <td>765.85</td>
                <td>796.24</td>
                <td>797.82</td>
                <td>796.46</td>
                <td>2018.09.02 05:30:00</td>              
        </tr>
                    
             
        <tr>
            <td>欧元</td>
            <td>790.41</td>
                <td>765.85</td>
                <td>796.24</td>
                <td>797.82</td>
                <td>796.46</td>
                <td>2018.09.02 05:30:00</td>              
        </tr>
                    
             
        <tr>
            <td>欧元</td>
            <td>790.41</td>
                <td>765.85</td>
                <td>796.24</td>
                <td>797.82</td>
                <td>796.46</td>
                <td>2018.09.02 05:30:00</td>              
        </tr>
                    
             
        <tr>
            <td>欧元</td>
            <td>790.41</td>
                <td>765.85</td>
                <td>796.24</td>
                <td>797.82</td>
                <td>796.46</td>
                <td>2018.09.02 05:30:00</td>              
        </tr>
                    
             
        <tr>
            <td>欧元</td>
            <td>790.41</td>
                <td>765.85</td>
                <td>796.24</td>
                <td>797.82</td>
                <td>796.46</td>
                <td>2018.09.02 05:30:00</td>              
        </tr>
                    
             
        <tr>
            <td>欧元</td>
            <td>790.41</td>
                <td>765.85</td>
                <td>796.24</td>
                <td>797.82</td>
                <td>796.46</td>
                <td>2018.09.01 05:30:00</td>              
        </tr>
                    
             
        <tr>
            <td>欧元</td>
            <td>790.41</td>
                <td>765.85</td>
                <td>796.24</td>
                <td>797.82</td>
                <td>796.46</td>
                <td>2018.09.01 05:30:00</td>              
        </tr>
                    
             
        <tr>
            <td>欧元</td>
            <td>790.41</td>
                <td>765.85</td>
                <td>796.24</td>
                <td>797.82</td>
                <td>796.46</td>
                <td>2018.09.02 00:00:05</td>              
        </tr>
                    
             
        <tr>
            <td>欧元</td>
            <td>790.41</td>
                <td>765.85</td>
                <td>796.24</td>
                <td>797.82</td>
                <td>796.46</td>
                <td>2018.09.01 05:30:00</td>              
        </tr>
                    
             
        <tr>
            <td>欧元</td>
            <td>790.41</td>
                <td>765.85</td>
                <td>796.24</td>
                <td>797.82</td>
                <td>796.46</td>
                <td>2018.09.01 05:30:00</td>              
        </tr>
                    
             
        <tr>
            <td>欧元</td>
            <td>790.41</td>
                <td>765.85</td>
                <td>796.24</td>
                <td>797.82</td>
                <td>796.46</td>
                <td>2018.09.01 05:30:00</td>              
        </tr>
                    
             
        <tr>
            <td>欧元</td>
            <td>790.41</td>
                <td>765.85</td>
                <td>796.24</td>
                <td>797.82</td>
                <td>796.46</td>
                <td>2018.09.01 04:52:28</td>              
        </tr>
                    
             
        <tr>
            <td>欧元</td>
            <td>789.45</td>
                <td>764.92</td>
                <td>795.27</td>
                <td>796.86</td>
                <td>796.46</td>
                <td>2018.09.01 00:11:15</td>              
        </tr>
                    
             
        <tr>
            <td>欧元</td>
            <td>789.52</td>
                <td>764.99</td>
                <td>795.34</td>
                <td>796.93</td>
                <td>796.46</td>
                <td>2018.09.01 00:00:13</td>              
        </tr>
                    
             
        <tr>
            <td>欧元</td>
            <td>790</td>
                <td>765.45</td>
                <td>795.83</td>
                <td>797.41</td>
                <td>796.46</td>
                <td>2018.09.01 00:00:05</td>              
        </tr>
                    
             
        <tr>
            <td>欧元</td>
            <td>790</td>
                <td>765.45</td>
                <td>795.83</td>
                <td>797.41</td>
                <td>796.46</td>
                <td>2018.08.31 23:52:31</td>              
        </tr>
                    
             
        <tr>
            <td>欧元</td>
            <td>790</td>
                <td>765.45</td>
                <td>795.83</td>
                <td>797.41</td>
                <td>796.46</td>
                <td>2018.08.31 23:52:31</td>              
        </tr>
                    
             
        <tr>
            <td>欧元</td>
            <td>790</td>
                <td>765.45</td>
                <td>795.83</td>
                <td>797.41</td>
                <td>796.46</td>
                <td>2018.08.31 23:52:31</td>              
        </tr>
                    
             
        <tr>
            <td>欧元</td>
            <td>790.64</td>
                <td>766.07</td>
                <td>796.47</td>
                <td>798.05</td>
                <td>796.46</td>
                <td>2018.08.31 23:22:05</td>              
        </tr>
                    
             
        <tr>
            <td>欧元</td>
            <td>790.8</td>
                <td>766.23</td>
                <td>796.63</td>
                <td>798.22</td>
                <td>796.46</td>
                <td>2018.08.31 23:18:43</td>              
        </tr>
                    
            

<tr>
    <td colspan="11" style="height:30px;">&nbsp;</td>
</tr>
</table>
<div class="pb_ft clearfix" style="width:500px;clear:both;">
    <div class="turn_page" id="list_navigator" style="margin-left:300px;">
                
    </div><!--翻页-->
</div><!--content--end-->
</div><!--发布-end-->
<script language="JavaScript">
    function executeSearch()
    {  
        document.historysearchform.method = 'post';  
        document.historysearchform.submit();
    } 
    PageContext.PageNav.go =  function(_iPage,_maxPage)
    {
        document.pageform.page.value = _iPage;
        document.pageform.submit();
    };
    //画分页代码以及自动调整窗口大小
    var m_nRecordCount = 1014;
    if(m_nRecordCount.length == 0){
        m_nRecordCount = 0;
    }
    var m_nCurrPage = 1;
    var m_nPageSize = 20;
    function init_list(){
        PageContext.params["RecordNum"] = m_nRecordCount;
        PageContext.params["CurrPage"] = m_nCurrPage;
        PageContext.params["PageSize"] = m_nPageSize;
        PageContext.drawNavigator(); 
    }
    function gotoPage(npage)
    { 
        document.pageform.page.value = npage;
        document.pageform.submit();
    }
    function getPage()
    { 
        var val = document.getElementById("currentPage").value;
        return val ;
    }
</script>

<script language="JavaScript" src="http://www.bankofchina.com/bottom.js"></script>
<script>
    createBottom();
</script>
<form name="pageform" action="search.jsp" method=post > 
    <input type="hidden" name="erectDate" value="2018-08-26"> 
    <input type="hidden" name="nothing" value="2018-09-02"> 
    <INPUT type="hidden" name="pjname" value="1326">  
    <input type="hidden" name="page" value="1">  
</form>  
</div>
</body>
</html> 

这个一整好像挺麻烦的,有没有更简单的方法呢?有!
表格信息原本是长这样的:


点击查看源(view source),可以切换成钩子形式,得来全不费功夫

早知如此何必费那个劲呢?(早知道就不那么搞)
我直接打开这个网页好不好?好的!毫无差别。

那直接就get得了,不用post了
import requests

url = 'http://srh.bankofchina.com/search/whpj/search.jsp?erectDate=2018-08-26&nothing=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即可。

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&nothing=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了,这篇结果我是开手机热点爬的(捂脸)。

相关文章

网友评论

      本文标题:09 使用Python爬取中国银行网站选择汇率最坑的一天

      本文链接:https://www.haomeiwen.com/subject/meztgftx.html