Python爬虫系列-获取每天黄金价格(编写爬虫的过程和编写代码思路详细解析)

        最近因为经济形势不好,黄金这样的硬通货价格持续走高,而且现在已经到了相当之高的程度。介于理财投资的低迷,黄金的长期投资说不定可以跑赢通胀。对于我们新手的投资,本着低买高卖的原则,总不会亏太多,这样我们就需要一个可以每天获取黄金价格的python脚本,每天爬取我们需要的黄金价格,然后大家可以根据需要添加发送邮件给自己等功能,做一个自动推送黄金价格的小工具。

        先在网上随便找一个黄金价格的网站,比如下面的这个链接:

今日中国黄金最新价格查询(中国基础金价多少钱一克)-行情中心-金投网 (cngold.org)icon-default.png?t=N7T8https://quote.cngold.org/gjs/swhj_zghj.html

如上图,我们可以看到,这个网站有每天的黄金基础价、零售价、回收价,下面的列表中有我们需要金价,点击上面的黄金基础价、零售价、回收价,下面的列表也会切换到相应的项目的价格上去,而我们的目标就是获取下面的列表中每天的金价了。

我们先试试edge浏览器的f12开发者调试模式,如下图:

切换到网络选项卡,按F5刷新网页,发现如下图:

那我们使用Fiddler直接抓包看看(你也可以使用Chrome浏览器的开发者模式抓包,这个网页不会报错,我想介绍给大家更通用的方法,所以使用了Fiddler)。打开我们的Fiddler Classic,随便选择一个左侧列表中嗅探出的网页项目,点击右上方Inspectors,并切换到JSON选项卡,如下图:

然后我们不停切换左侧列表嗅探出的网页,并观察右下角的JSON窗口的内容变化,当切换到

https://api.jijinhao.com/quoteCenter/historys.htm?codes=JO_52683&style=3&pageSize=30&_=1708922877928

 以上链接时,如下图:

可以看到JSON窗口返回了我们需要的黄金单价,和网页中比较下,发现它是和网页的排除顺序相反,最新日期的数据是在最后的,而且通过这个网址传递的参数分析,它的参数如下:

codes=JO_52683

style=3

pageSize=30

time=1708922877928

显然其中的codes是切换黄金基础价、零售价、回收价的,一共有三种格式:

黄金基础价: JO_52683

零售价: JO_52684

回收价: JO_52685

style显示是一个类型,我们暂时不需要,pageSize是每次使用这个网址请求服务器返回数据时,服务器返回的数据条数数,pageSize=30就是返回30条数据,经过我用python的request发包测试,最少可以返回1条,最多返回500条数据。最后的time时间戳没有写明,但显然就是一个毫秒级时间戳(代表当前日期时间),实际测试时发现服务器并不验证这个时间戳,也就是重复传一个固定的时间戳也可以,当然我在我的代码中还是模拟了下当前时间戳。

# 将日期字符串转换为datetime对象
def date_to_time(date):date_format = '%Y-%m-%d'date_obj = datetime.strptime(date, date_format)# 获取UTC时间的时间戳(秒)timestamp_seconds = date_obj.timestamp()# 转换为毫秒timestamp_milliseconds = int(timestamp_seconds * 1000)return timestamp_milliseconds

下面是我用python构造了模拟发包获取服务器返回的json数据的函数:

def getPageData(pageSize,pagecount,data_style,header,time):res = requests.get("https://api.jijinhao.com/quoteCenter/historys.htm?codes=" + data_style + "&style=3&pageSize=" + str(pageSize) + "&currentPage=" + str(pagecount) + "&_=" + str(time),headers = header)# 获得json变量,里面记录着金价和记录日期quote_json_str = res.content.decode("utf-8")#print(quote_json_str)quote_json = json.loads(quote_json_str[4:].replace("quote_json = ",""))printout(pagecount,pageSize,quote_json,data_style)

 我来解释下这个函数,第一句是使用requests库的get方法,通过传入我们构造的参数url网址和header发包头,来模拟发送给服务器,使之返回我们需要的json结果,其中pageSize(每页数量),pagecount(返回总页数),data_style(金价的类型),header(网页发送时的请求头),time(当前时间戳)都是我们构造函数的模拟参数,通过调用此函数时自定义传入即可。第二句是按照utf-8的格式转码我们获得的服务器返回值。因为服务器返回的是如下面格式字符串(以下的返回值我已做过格式化处理方便大家查看):

'var quote_json = {"flag": True,"style": 3,"data": {"JO_52683_digits": 2,"JO_52683_status": 100,"JO_52683_unit": "元/克","JO_52683_productName": "中国黄金基础金价","JO_52683": [{"q1": 480.0,"q2": 480.0,"q3": 480.0,"q4": 480.0,"q60": 1.0,"q62": 0.0,"time": 1708617600000}]}
}'

因此我们需把上面的字符串转换成我们可以操作的json格式,所以先用第三句的去掉这个字符串的参数名'var quote_json =,然后把这个字符串放入json.loads函数中载入成标准的json数据格式方便操作。我们观察下上面的序列构造,显然我们只需要JO_52683数组中的q1和time时间戳(此时间戳是金价数据对应的日期),经过一番构造后,有了如下函数:

def printout(pagecount,pageSize,json_data,data_style):#data_style表示返回金价类型:{'基础':'JO_52683','零售':'JO_52684','回收':'JO_52685'}count = 0for index in range(pageSize-1,-1,-1):#逆循环,因为返回每页的json都是从早的日期开始排列的,如果要使每页从比较晚的数据排列需要倒叙循环.item = json_data["data"][data_style][index]count += 1date = time_to_date(item["time"])if data_style == "JO_52683":price_style = "基础"elif data_style == "JO_52684":price_style = "零售"else:price_style = "回收"print(f"第{pagecount}页_{count}:日期:{date}, {price_style}金价:{item['q1']}元")

其中,一共4个参数,其他之前后已介绍过,json_data就是我们上一步获得的json格式数据,我们需要在这个函数中,解析出我们需要的数据。因为返回的json是逆序的日期排列,也就是最新的日期金价在最后面,我们我们需要逆循环读取出数据。

要逆向循环,即从高到低循环,你可以使用range函数的三个参数:起始值、结束值和步长。当步长为负数时,可以实现逆向循环。如果你想要从pageSize - 1开始到0结束(包含0),你可以这样做:

for index in range(pageSize - 1, -1, -1): # 你的代码

这里的range(pageSize - 1, -1, -1)解释如下:

  • pageSize - 1是循环的起始值,因为range在Python中是包含起始值、不包含结束值的,所以要从pageSize - 1开始。
  • -1是循环应该停止的值的前一个位置。由于不包括这个值本身,如果你想循环到0,你需要写-1作为结束值。
  • -1是每次循环中索引减少的量,即步长。

然后我们构造一个item变量,读取data键值中的"JO_52683"数组,也就是前面序列中的

"JO_52683": [{"q1": 480.0,"q2": 480.0,"q3": 480.0,"q4": 480.0,"q60": 1.0,"q62": 0.0,"time": 1708617600000}]

然后我们通过使用item["q1"]和item["time"]取出每个数组中的金价和日期时间戳就行了,然后通过下面的函数把时间戳转换成相应的日期格式:

def time_to_date(time):# 时间戳转换为日期timestamp = time / 1000 + 24 * 60 * 60  # 将毫秒转换为秒,因为是UTC时间需加24小时*60分钟*60秒return datetime.utcfromtimestamp(timestamp).strftime('%Y-%m-%d')

其中因为时间戳是UTC格式,是美国东时间,所以还要增加24小时*60分钟*60秒,因为是毫秒级需除以1000转换成秒,因此最终格式为timestamp = time / 1000 + 24 * 60 * 60,然后通过datetime.utcfromtimestamp函数的strftime转换成2024-02-26这样的格式即可。

最后我们只要把所有函数串联起来调用即可,如下面的完整代码:

import requests
from bs4 import BeautifulSoup as bs4
from datetime import datetime
import json
import timedef time_to_date(time):# 时间戳转换为日期timestamp = time / 1000 + 24 * 60 * 60  # 将毫秒转换为秒,因为是UTC时间需加24小时*60分钟*60秒return datetime.utcfromtimestamp(timestamp).strftime('%Y-%m-%d')def date_to_time(date):# 将日期字符串转换为datetime对象date_format = '%Y-%m-%d'date_obj = datetime.strptime(date, date_format)# 获取UTC时间的时间戳(秒)timestamp_seconds = date_obj.timestamp()# 转换为毫秒timestamp_milliseconds = int(timestamp_seconds * 1000)return timestamp_millisecondsdef printout(pagecount,pageSize,json_data,data_style):#data_style表示返回金价类型:{'基础':'JO_52683','零售':'JO_52684','回收':'JO_52685'}count = 0for index in range(pageSize-1,-1,-1):#逆循环,因为返回每页的json都是从早的日期开始排列的,如果要使每页从比较晚的数据排列需要倒叙循环.item = json_data["data"][data_style][index]count += 1date = time_to_date(item["time"])if data_style == "JO_52683":price_style = "基础"elif data_style == "JO_52684":price_style = "零售"else:price_style = "回收"print(f"第{pagecount}页_{count}:日期:{date}, {price_style}金价:{item['q1']}元")def getPageData(pageSize,pagecount,data_style,header,time):res = requests.get("https://api.jijinhao.com/quoteCenter/historys.htm?codes=" + data_style + "&style=3&pageSize=" + str(pageSize) + "&currentPage=" + str(pagecount) + "&_=" + str(time),headers = header)# 获得json变量,里面记录着金价和记录日期quote_json_str = res.content.decode("utf-8")#print(quote_json_str)quote_json = json.loads(quote_json_str[4:].replace("quote_json = ",""))printout(pagecount,pageSize,quote_json,data_style)header = {'Host': 'api.jijinhao.com','Connection': 'keep-alive','sec-ch-ua': '"Not A(Brand";v="99", "Microsoft Edge";v="121", "Chromium";v="121"','sec-ch-ua-mobile': '?0','User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36 Edg/121.0.0.0','sec-ch-ua-platform': '"Windows"','Accept': '*/*','Sec-Fetch-Site': 'cross-site','Sec-Fetch-Mode': 'no-cors','Sec-Fetch-Dest': 'script','Referer': 'https://quote.cngold.org/gjs/swhj_zghj.html','Accept-Encoding': 'gzip, deflate, br','Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6','Content-Type': 'text/html;charset=UTF-8','Connection': 'keep-alive',}def main():# 以下注释代码可以直接传入今天的日期date_str = datetime.now().strftime('%Y-%m-%d')# 把当前日期传入转换函数后,获得如"1708656891526"这样的毫秒时间戳time = date_to_time(date_str)#print(time)#设置获得的金价数据条目数(可以设置1-500,但是因为分页数关系,可能最后的一页会报错,设置值越大爬取越快,如果要完整爬取请使用默认值10)pageSize = 10#data_style表示返回金价类型:{'基础':'JO_52683','零售':'JO_52684','回收':'JO_52685'}data_style = 'JO_52684'count = 0#爬取你需要的总页数pageMax= 313while (count <= pageMax):getPageData(pageSize,count,data_style,header,time)count += 1if __name__ == "__main__":main()

其中的pageMax是你需要爬取的页数,取的大一点不要紧,因为爬取不到数据会报错停下。请看如下的爬取结果: 

以上是我的爬虫教程,给大家学习参考用,请不要把爬虫用于不良目的,爬取测试时请添加延时,不要增加服务器负担,谢谢观看!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/492436.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于容器和集群技术的数据自动化采集设计和实现

目标&#xff1a;部署mysql服务容器并使用docker构建包含python爬虫脚本的容器采集数据到mysql数据库。 环境&#xff1a;Centos7、已配置Kubernetes集群及docker。 环境配置请参考以下文章&#xff1a; CentOS7搭建Kubernetes集群 Kubernetes集群信息如下(虚拟机主机名和IP…

Mac使用K6工具压测WebSocket

commend空格 打开终端&#xff0c;安装k6 brew install k6验证是否安装成功 k6 version设置日志级别为debug export K6_LOG_LEVELdebug执行脚本&#xff08;进入脚本所在文件夹下&#xff09; k6 run --vus 100 --duration 10m --out csvresult.csv script.js 脚本解释&…

计算机设计大赛 深度学习图像风格迁移 - opencv python

文章目录 0 前言1 VGG网络2 风格迁移3 内容损失4 风格损失5 主代码实现6 迁移模型实现7 效果展示8 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 深度学习图像风格迁移 - opencv python 该项目较为新颖&#xff0c;适合作为竞赛课题…

【小沐学QT】QT学习之Web控件的使用

文章目录 1、简介1.1 Qt简介1.2 Qt下载和安装1.3 Qt快捷键1.4 Qt帮助 2、QtWeb控件2.1 测试代码1&#xff08;QApplication&#xff09;2.2 测试代码2&#xff08;QApplicationQWidget&#xff09;2.3 测试代码3&#xff08;QApplicationQMainWindow&#xff09;2.4 测试代码4&…

如何做代码的Review:一场细致入微的质量把控之旅

我是洋哥&#xff0c;一个拥有6年经验的程序员&#xff0c;Litchi开源组织发起人。 在软件开发中&#xff0c;代码Review是一个至关重要的环节。它不仅是保证代码质量的有效手段&#xff0c;还是团队成员之间交流经验、共享知识的桥梁。本文将带你走进代码Review的世界&#xf…

hcia datacom课程学习(1):通信基础

1.总体框架 上图为发送方通过互联网传递信息给接收方的过程。 家用路由器会直接集成上图中的四层&#xff08;vlan&#xff0c;DHCP&#xff0c;静态路由&#xff0c;NAT&#xff0c;PPPoE&#xff09;。 2.网络性能指标 &#xff08;1&#xff09;带宽 单位时间内传输的数…

稳态准直大面积太阳光模拟器中光学系统

太阳光模拟器中光学系统概述 光学系统&#xff08;optical system&#xff09;是指由透镜、反射镜、棱镜和光阑等多种光学元件按一定次序组合成的系统。通常用来成像或做光学信息处 理。曲率中心在同一直线上的两个或两个以上折射&#xff08;或反射&#xff09;球面组成的光学…

【web】云导航项目部署及环境搭建(复杂)

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、项目介绍1.1项目环境架构LNMP1.2项目代码说明 二、项目环境搭建2.1 Nginx安装2.2 php安装2.3 nginx配置和php配置2.3.1 修改nginx文件2.3.2 修改vim /etc/p…

300分钟吃透分布式缓存-14讲:大数据时代,MC如何应对新的常见问题?

大数据时代 Memcached 经典问题 随着互联网的快速发展和普及&#xff0c;人类进入了大数据时代。在大数据时代&#xff0c;移动设备全面融入了人们的工作和生活&#xff0c;各种数据以前所未有的 速度被生产、挖掘和消费。移动互联网系统也不断演进和发展&#xff0c;存储、计…

代码随想录day34--动态规划的应用2 | LeetCode343.整数拆分、LeetCode96.不同的二叉搜索树

LeetCode343.整数拆分 题目描述&#xff1a; 给定一个正整数 n &#xff0c;将其拆分为 k 个 正整数 的和&#xff08; k > 2 &#xff09;&#xff0c;并使这些整数的乘积最大化。 返回 你可以获得的最大乘积 。 示例 1: 输入: n 2 输出: 1 解释: 2 1 1, 1 1 1。…

深入理解计算机系统学习笔记

2.3整数运算 有时候会发现两个正数相加会得出一个负数&#xff0c;而比较表达式x<y和比较表达式x-y<0会产生不同的结果。这些属性是由于计算机运算的有限性造成的。理解计算机运算的细微之处能够帮助程序员编写更可靠的代码。 2 .3. 1 无符号加法 原理&#xff1a; 在正…

什么是媒体发稿?发稿媒体分类及发稿流程

传媒如春雨&#xff0c;润物细无声&#xff0c;大家好&#xff0c;我是51媒体网胡老师。 媒体发稿是一种企业推广和宣传的手段&#xff0c;通过媒体渠道传递企业信息和形象。 媒体发稿的含义在于&#xff0c;当企业有新闻、事件或其他消息需要对外公布时&#xff0c;可以选择…