文章目录

  • 1 背景
  • 2 环境
  • 3 代码
    • 3.1 Yahoo汇率(内地IP可以跳过)
    • 3.2 中银汇率
    • 3.3 监测
    • 3.4 运行
    • 3.5 整体代码
  • 4 运行效果

1 背景

作者现在在香港,最近半年因为美国加息,港币暴涨,非常痛苦。在网上找了找也没有找到能够实时更新的API来调用。为了能在偶尔出现汇率下降的时候及时购汇,写了一个监测Yahoo和中银汇率的Python脚本。

结尾有整个Python代码。

2 环境

  • 建议可以跑在服务器上可以一直运行
  • Python3

要引入的包:

import random
import sysimport requests
from lxml import etree
from hyper.contrib import HTTP20Adapter
import smtplib
from email.mime.text import MIMEText
from email.header import Header
import datetime
import time

哪个没有直接pip install一下就行了。

3 代码

本质上就是给相应页面的服务器发送Http请求获取html页面内容之后再Xpath来解析。不过先用浏览器进入F12检查一下携带的headers和参数,再用requests工具发送就可以模拟浏览器而不被拒绝了。

至于怎么获取请求头和参数,在浏览器进入检查界面后,进入带有汇率的页面,查看网络一栏下哪一个请求到了想要的数据,把url,headers和参数都记下来就行了(你也可以直接使用我的headers试试),在Python中用字典的形式来保存。

如果你需要其他货币的汇率,更换一下下面代码中的url就可以了。下面的url中都带了一个时间戳的参数防止缓存。

3.1 Yahoo汇率(内地IP可以跳过)

def get_yahoo_hk_currency():url = 'https://finance.yahoo.com/quote/HKDCNY=X?p=HKDCNY=X&.tsrc=fin-srch&timestamp=' + str(time.time())headers = {':method': 'GET', ':scheme': 'https', ':authority': 'finance.yahoo.com',':path': '/quote/HKDCNY=X?p=HKDCNY=X&.tsrc=fin-srch','Cookie': 'A1=d=AQABBDHvM2MCECI2mmBLq9Wjg_CpwqrHHxgFEgEBBwE2WmODY1iia3sB_eMBAAcIMe8zY6rHHxg&S=AQAAAkClup8wRI-xsJF1yi6vqII; A1S=d=AQABBDHvM2MCECI2mmBLq9Wjg_CpwqrHHxgFEgEBBwE2WmODY1iia3sB_eMBAAcIMe8zY6rHHxg&S=AQAAAkClup8wRI-xsJF1yi6vqII&j=WORLD; A3=d=AQABBDHvM2MCECI2mmBLq9Wjg_CpwqrHHxgFEgEBBwE2WmODY1iia3sB_eMBAAcIMe8zY6rHHxg&S=AQAAAkClup8wRI-xsJF1yi6vqII; B=1g7u7l9hj7rph&b=3&s=sc; PRF=t%3DCNY%253DX; maex=%7B%22v2%22%3A%7B%7D%7D; __gpi=UID=00000894058aa89c:T=1666772728:RT=1666772728:S=ALNI_Mbzrr-RS-qdoaBtUlK4qMHoR4fTOw; GUC=AQEBBwFjWjZjg0IdJwR0; cmp=t=1666772723&j=0&u=1---; GUCS=ATweDAh7','Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8','Host': 'finance.yahoo.com','User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.1 Safari/605.1.15','Accept-Language': 'zh-CN,zh-Hans;q=0.9', 'Accept-Encoding': 'gzip, deflate, br','Connection': 'keep-alive'}params = {'p': 'HKDCNY=X', '.tsrc': 'fin-srch'}sessions = requests.session()sessions.mount(url, HTTP20Adapter())res = sessions.get(url, headers=headers, params=params)dom = etree.HTML(res.text)cur = dom.xpath('/html/body//div[@class="D(ib) Mend(20px)"]/fin-streamer')return float(cur[0].text) if len(cur) > 0 else -1

下面是Yahoo带有汇率的html,蓝色部分是我们想要的汇率信息。

函数中用到的Xpath语法照着这张图估计也就差不多能明白了(//表示的是无视层级的查找)。

3.2 中银汇率

跟上面的原理类似,但是中银这个页面(居然还是jsp)请求更加简单,不需要请求头就行。

def get_boc_hk_currency():url = 'https://srh.bankofchina.com/search/whpj/search_cn.jsp'params = {'erectDate': None, 'nothing': None, 'pjname': '港币', 'head': 'head_620.js', 'bottom': 'bottom_591.js','t': random.random()}sessions = requests.session()sessions.mount(url, HTTP20Adapter())res = sessions.get(url, params=params)dom = etree.HTML(res.text)tds = dom.xpath('/html/body//div[@class="BOC_main publish"]//tr[2]/td')# 购汇buy_currency = round(float(tds[3].text) / 100, 4)# 结汇sale_currency = round(float(tds[1].text) / 100, 4)return buy_currency, sale_currency

3.3 监测

汇率能够获取到了,剩下的逻辑就可以按照自己的需求来写了。

我这里是监测到和上次记录的值不相等就发送一封电子邮件给自己。使用到了email包,要注意的是,使用QQ邮箱这种进行发送的时候,密码不是你的QQ密码,要去QQ邮箱页面开启SMTP服务(不清楚的可以百度查),使用提供的授权码作为密码。

开头部分这里接收邮箱通过命令行参数的形式来接收(第一个命令行参数是脚本的文件名,所以收集完删掉第一个元素del(to_addrs[0])),也可以直接写死。剩下的代码就很好理解了。死循环结尾是让线程睡眠一段时间,给个随机值降低被检测出来是脚本的可能。

if __name__ == '__main__':# sys.stdout.flush()to_addrs = []from_addr = "?@163.com"for email in sys.argv:to_addrs.append(email)del (to_addrs[0])# 记录上一次yahoo购汇发送的汇率和时间last_yahoo_currency = -1last_boc_buy_currency = -1last_boc_sale_currency = -1last_time = '初始化运行无数据,已记录本次'while True:try:yahoo_currency = get_yahoo_hk_currency()boc_buy_currency, boc_sale_currency = get_boc_hk_currency()print(str(datetime.datetime.now()) + ' ' + str(yahoo_currency) + ' ' + str(boc_buy_currency) + ' ' + str(boc_sale_currency))if last_boc_buy_currency == -1 or (last_yahoo_currency != -1 and last_yahoo_currency != yahoo_currency) \or last_boc_buy_currency != boc_buy_currency:print("监测到变化。")cur_time = str(datetime.datetime.now())msg_str = f'''{cur_time}[yahoo]\t\t{yahoo_currency}[boc购汇]\t{boc_buy_currency}[boc结汇]\t{boc_sale_currency}-------------------(上一次中银购汇汇率){last_time}{last_boc_buy_currency}'''# 创建 SMTP 对象mail_server = "smtp.163.com"smtp = smtplib.SMTP_SSL(mail_server)smtp.connect(mail_server, port=465)# 登录,需要:登录邮箱和授权码smtp.login(user=from_addr, password="?")msg = MIMEText(msg_str, 'plain', 'utf-8')msg['From'] = Header('URAC')msg['Subject'] = Header('港币汇率更新提醒', 'utf-8')smtp.sendmail(from_addr=from_addr,to_addrs=to_addrs, msg=msg.as_string())smtp.quit()smtp.close()last_yahoo_currency = yahoo_currencylast_boc_buy_currency = boc_buy_currencylast_boc_sale_currency = boc_sale_currencylast_time = str(cur_time)except BaseException as e:traceback.print_exc()finally:sys.stdout.flush()time.sleep(30 - random.randint(-9, 9))

3.4 运行

在服务器(或者自己电脑上)上执行nohup python3 currency.py 1@qq.com 2@qq.com &就能够在后台持续执行了。

3.5 整体代码

import random
import sysimport requests
from lxml import etree
from hyper.contrib import HTTP20Adapter
import smtplib
from email.mime.text import MIMEText
from email.header import Header
import datetime
import time
import tracebackdef get_yahoo_hk_currency():url = 'https://finance.yahoo.com/quote/HKDCNY=X?p=HKDCNY=X&.tsrc=fin-srch&timestamp=' + str(time.time())headers = {':method': 'GET', ':scheme': 'https', ':authority': 'finance.yahoo.com',':path': '/quote/HKDCNY=X?p=HKDCNY=X&.tsrc=fin-srch','Cookie': 'A1=d=AQABBDHvM2MCECI2mmBLq9Wjg_CpwqrHHxgFEgEBBwE2WmODY1iia3sB_eMBAAcIMe8zY6rHHxg&S=AQAAAkClup8wRI-xsJF1yi6vqII; A1S=d=AQABBDHvM2MCECI2mmBLq9Wjg_CpwqrHHxgFEgEBBwE2WmODY1iia3sB_eMBAAcIMe8zY6rHHxg&S=AQAAAkClup8wRI-xsJF1yi6vqII&j=WORLD; A3=d=AQABBDHvM2MCECI2mmBLq9Wjg_CpwqrHHxgFEgEBBwE2WmODY1iia3sB_eMBAAcIMe8zY6rHHxg&S=AQAAAkClup8wRI-xsJF1yi6vqII; B=1g7u7l9hj7rph&b=3&s=sc; PRF=t%3DCNY%253DX; maex=%7B%22v2%22%3A%7B%7D%7D; __gpi=UID=00000894058aa89c:T=1666772728:RT=1666772728:S=ALNI_Mbzrr-RS-qdoaBtUlK4qMHoR4fTOw; GUC=AQEBBwFjWjZjg0IdJwR0; cmp=t=1666772723&j=0&u=1---; GUCS=ATweDAh7','Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8','Host': 'finance.yahoo.com','User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.1 Safari/605.1.15','Accept-Language': 'zh-CN,zh-Hans;q=0.9', 'Accept-Encoding': 'gzip, deflate, br','Connection': 'keep-alive'}params = {'p': 'HKDCNY=X', '.tsrc': 'fin-srch'}sessions = requests.session()sessions.mount(url, HTTP20Adapter())res = sessions.get(url, headers=headers, params=params)dom = etree.HTML(res.text)cur = dom.xpath('/html/body//div[@class="D(ib) Mend(20px)"]/fin-streamer')return float(cur[0].text) if len(cur) > 0 else -1def get_boc_hk_currency():url = 'https://srh.bankofchina.com/search/whpj/search_cn.jsp'params = {'erectDate': None, 'nothing': None, 'pjname': '港币', 'head': 'head_620.js', 'bottom': 'bottom_591.js','t': random.random()}sessions = requests.session()sessions.mount(url, HTTP20Adapter())res = sessions.get(url, params=params)dom = etree.HTML(res.text)tds = dom.xpath('/html/body//div[@class="BOC_main publish"]//tr[2]/td')# 购汇buy_currency = round(float(tds[3].text) / 100, 4)# 结汇sale_currency = round(float(tds[1].text) / 100, 4)return buy_currency, sale_currencyif __name__ == '__main__':# sys.stdout.flush()to_addrs = []from_addr = "?@163.com"for email in sys.argv:to_addrs.append(email)del (to_addrs[0])# 记录上一次yahoo购汇发送的汇率和时间last_yahoo_currency = -1last_boc_buy_currency = -1last_boc_sale_currency = -1last_time = '初始化运行无数据,已记录本次'while True:try:yahoo_currency = get_yahoo_hk_currency()boc_buy_currency, boc_sale_currency = get_boc_hk_currency()print(str(datetime.datetime.now()) + ' ' + str(yahoo_currency) + ' ' + str(boc_buy_currency) + ' ' + str(boc_sale_currency))if last_boc_buy_currency == -1 or (last_yahoo_currency != -1 and last_yahoo_currency != yahoo_currency) \or last_boc_buy_currency != boc_buy_currency:print("监测到变化。")cur_time = str(datetime.datetime.now())msg_str = f'''{cur_time}[yahoo]\t\t{yahoo_currency}[boc购汇]\t{boc_buy_currency}[boc结汇]\t{boc_sale_currency}-------------------(上一次中银购汇汇率){last_time}{last_boc_buy_currency}'''# 创建 SMTP 对象mail_server = "smtp.163.com"smtp = smtplib.SMTP_SSL(mail_server)smtp.connect(mail_server, port=465)# 登录,需要:登录邮箱和授权码smtp.login(user=from_addr, password="?")msg = MIMEText(msg_str, 'plain', 'utf-8')msg['From'] = Header('URAC')msg['Subject'] = Header('港币汇率更新提醒', 'utf-8')smtp.sendmail(from_addr=from_addr,to_addrs=to_addrs, msg=msg.as_string())smtp.quit()smtp.close()last_yahoo_currency = yahoo_currencylast_boc_buy_currency = boc_buy_currencylast_boc_sale_currency = boc_sale_currencylast_time = str(cur_time)except BaseException as e:traceback.print_exc()finally:sys.stdout.flush()time.sleep(30 - random.randint(-9, 9))

4 运行效果

问题1 在CentOS上运行,发不出邮件也不报错
解决 这个问题困扰我很久,网上说是没有使用SMTP_SSL来连接,但是刚开始使用的时候 是能发出来的。然后还有一个情况是发送一阵之后就又不发送了,网上查到是需要定期quit()重新登录才行,不然会自动退出。

【练习/Python】监测汇率脚本相关推荐

  1. [转载] python中断响应_用Python脚本监测.py脚本的进程状态,并实现中断重启。

    参考链接: Python中断并继续 用Python脚本监测.py脚本的执行状态,并实现中断重启. #!/usr/bin/python # -*- coding:utf-8 -*- import sub ...

  2. python selenium脚本_怎样开始写第一个基于python的selenium脚本

    1.下载并安装python(http://www.python.org/geti/). 2.安装selenium(http://pypi.python.org/pypi/selenium)下载并解压缩 ...

  3. python自动化办公脚本下载-python自动化脚本

    广告关闭 腾讯云双11爆品提前享,精选热门产品助力上云,云服务器首年88元起,买的越多返的越多,最高满返5000元! 运维自动化,已经成为运维必不可少的一部分,下面附上自己写的监控nginx_stat ...

  4. 脚本编程语言python语言-python语言是脚本语言吗

    Python是一种编程语言还是脚本语言? Python是GuidoVanRossum开发的最著名的编程语言之一.Python在开发人员中很受欢迎,因为它具有清晰的语法和简单的代码,甚至对于初学者来说也 ...

  5. Linux在后台运行python程序、脚本程序、可执行程序等,关闭终端仍可保持程序运行

    欢迎大家关注笔者,你的关注是我持续更博的最大动力 原创文章,转载告知,盗版必究 Linux在后台运行python程序.脚本程序.可执行程序等,关闭终端仍可保持程序运行 文章目录: 1 为什么需要后台运 ...

  6. 在IIS中写Python的CGI脚本

    原文:怎样在IIS中写Python的CGI脚本 1.安装好Python: 2.配置IIS:         a.打开管理工具-〉Internet信息服务:         b.在网站属性上右键,进入属 ...

  7. Python 调用shell脚本

    python调用Shell脚本,有两种方法:os.system(cmd)或os.popen(cmd),前者返回值是脚本的退出状态码,后者的返回值是脚本执行过程中的输出内容. 实际使用时视需求情况而选择 ...

  8. python调用Shell脚本:os.system(cmd)或os.popen(cmd),

    python调用Shell脚本,有两种方法:os.system(cmd)或os.popen(cmd),前者返回值是脚本的退出状态码,后者的返回值是脚本执行过程中的输出内容.实际使用时视需求情况而选择. ...

  9. Python语言学习:利用python语言实现调用内部命令(python调用Shell脚本)—命令提示符cmd的几种方法

    Python语言学习:利用python语言实现调用内部命令(python调用Shell脚本)-命令提示符cmd的几种方法 目录 利用python语言实现调用内部命令-命令提示符cmd的几种方法 T1. ...

最新文章

  1. 项目管理协作软件,打造超强执行力团队!
  2. java读取文件路径中文,分分钟搞定!
  3. linux作业(第四章练习题)
  4. 3月份GitHub上最热门的开源项目
  5. [C++11]智能指针简单介绍
  6. 信号量与令牌桶_限流的4种方式令牌桶实战
  7. 开发iOS即时通讯工具参考的一些开源、框架和教程
  8. Jedis使用java连接Redis
  9. java list详解_java集合List解析
  10. antd如何获取表单的值_Antd如何通过父组件直接获取子组件内表单值
  11. 就算不偷盗,也让你看看计算机里常用的有那些软件--常用软件序列号
  12. Qt浅谈之三十二二维码条形码解析
  13. ODB++ 数据格式解析软件
  14. 几个免费的高清图片网站推荐
  15. python统计股票上涨天数
  16. 数据结构期末考试错点汇总
  17. Android手机拍照或从本地相册选取图片设置头像。适配小米、华为、7.0
  18. Marvin is plain Jane WriteUp_实验吧_Crypto
  19. as ssd测试软件得分分析,固态硬盘性能测试软件AS SSD benchmark详解
  20. 搞机吧 | 刷rec、线刷、卡刷教程

热门文章

  1. 敏捷领导力2.0培训体会
  2. c语言中ANSI标准的关键字,C语言中32个关键字详解
  3. matlab 写netcdf,写入 netCDF 属性
  4. SpringBoot源码分析(二)之自动装配demo
  5. Linux系统程序包管理工具-RPM
  6. cesium接入百度影像地图(cesium篇.27)
  7. python积木编程软件_积木编程软件手机版下载
  8. win101909要不要更新_win101909更新了哪些内容?Win10 1909千万别更新原因
  9. 什么是视频内容推荐引擎?
  10. 《支付机构外汇业务管理办法》正式发布 合作银行不得超过2家