实战+代码!Selenium + Phantom JS爬取天天基金数据

 

功能:

通过程序实现从基金列表页,获取指定页数内所有基金的近一周收益率以及每支基金的详情页链接。再进入每支基金的详情页获取其余的基金信息,将所有获取到的基金详细信息按近6月收益率倒序排列写入一个Excel表格。

思路:

1. 通过实例化Tiantian_spider类的对象,初始化一个PhantomJS浏览器对象

2. 使用浏览器对象访问天天基金近六月排行的页面,获取该页面的源码

3. 从源码从获取每支基金所在的行(可以指定要获取基金的页数)

图片

4,从每行中获取每支基金的近1周收益率和基金详情链接

图片

5. 获取到每个基金的详情链接后,使用多进程分别进入每支基金的详情页面

6. 进入详情页后,获取基金的相关信息,并存入列表

图片

7. 将从所有基金的基金详情与在列表页获取的基金近1周收益率拼接后存入列表

8. 再将所有信息写入Excel表格

图片

  1. from selenium import webdriver

  2. from lxml import etree

  3. import time

  4. from openpyxl import Workbook

  5. import multiprocessing

  6. import re

  7. class Tiantian_spider():

  8. def __init__(self):

  9. self.driver = webdriver.PhantomJS() #指定的PhantomJS浏览器创建浏览器对象

  10. self.html = None

  11. self.next_page = True

  12. self.fund_url_list = []

  13. #1 发起请求

  14. def parser_url(self):

  15. # if self.next_page :

  16. # 点击页面进行翻页

  17. # label[last()]---》定位到最后一个label,即<label value="xx">下一页</label>

  18. # last()是一个函数,表示取最后一个

  19. self.driver.find_element_by_xpath("//div[@id='pagebar']/label[last()]").click()

  20. time.sleep(4) # 网页返回数据需要时间

  21. self.html = self.driver.page_source

  22. def parser_data_for_url(self):

  23. '''从基金列表页获取每支基金的近一周收益和详情链接'''

  24. # 解析字符串格式的HTML文档对象,将传进去的字符串转变成_Element对象

  25. html = etree.HTML(self.html)

  26. tr_list = html.xpath("//table[@id ='dbtable']//tbody/tr")

  27. next_page = html.xpath("//div[@id ='pagebar']//label[last()]")

  28. for tr in tr_list:

  29. tds =tr.xpath("./td")

  30. # 将近一周收益和详情链接组成的元组加入fund_url_list列表

  31. self.fund_url_list.append((str(tds[8].text),str(tds[2].xpath("./a/@href")[0])))

  32. return next_page # 返回下一页

  33. #翻页控制器

  34. def over_page(self,next_page):

  35. # 获取最后一页

  36. kw = next_page[0].xpath("./label[contains(@class,'end')]")

  37. # print(kw)

  38. # 判断是否是最后一页,如果是,则返回False,否则返回True

  39. flag = True if len(kw)==0 else False

  40. return flag

  41. def get_every_fund_url(self, url, page):

  42. # page:要获取前多少页的基金数据

  43. # 1 发起请求

  44. # 2 获取数据,解析数据

  45. self.driver.get(url)

  46. self.html = self.driver.page_source

  47. # 当页数不为0且还有下一页时,执行下面的操作

  48. while page > 0 and self.next_page:

  49. next_page= self.parser_data_for_url()

  50. # 4 翻页继续爬取

  51. self.next_page = self.over_page(next_page)

  52. # 如果不是下一页,就继续翻页

  53. if self.next_page:

  54. self.parser_url()

  55. page -= 1

  56. # 返回每支基金近一周收益和详情链接

  57. return self.fund_url_list

  58. def close_driver(self):

  59. self.driver.quit()

  60. def save_data(data):

  61. wb = Workbook() # 新创建一个文件

  62. ws = wb.active # 获取当前正在运行的工作表/激活工作表

  63. #将数据一行一行插入到工作表中

  64. #列表第一个元素将作为标题

  65. for i in data:

  66. ws.append(i)

  67. wb.save("近6月基金排名_" + time.strftime('%Y%m%d%H%M%S')+".xlsx")

  68. # 多进程任务函数

  69. # 获取进入基金的详情页获取详细信息

  70. def run(url, nearly_1_week):

  71. driver = webdriver.PhantomJS()

  72. driver.get(url)

  73. page_html = etree.HTML(driver.page_source) # 获取页面源码

  74. #获取基金名称

  75. #通过xpath或者的是一个元素列表,要元素下面的子元素,需要取某个具体的元素,不能用列表取

  76. fund_name =page_html.xpath("//div[@class='fundDetail-tit']/div/text()")[0]

  77. #获取基金代码类名

  78. fund_code_class_name = page_html.xpath("//div[@class='fundDetail-tit']/div/span[last()]/@class")[0]

  79. #根据代码类名判断基金代码只有一个,还是有前后端两个

  80. if fund_code_class_name == "ui-num":

  81. fund_code = page_html.xpath("//div[@class='fundDetail-tit']/div/span[last()]/text()")[0]

  82. elif fund_code_class_name == "fundcodeInfo":

  83. fund_code_info = page_html.xpath("//div[@class='fundDetail-tit']/div/span[@class='fundcodeInfo']")[0]

  84. fund_code = "前端: " +fund_code_info.xpath("./span[1]/text()")[0] + " 后端: " + fund_code_info.xpath("./span[2]/text()")[0]

  85. #收益和净值所在的上层div

  86. data_of_fund = page_html.xpath("//div[@class='dataOfFund']")[0]

  87. #近1月

  88. nearly_1_month =data_of_fund.xpath("./dl[1]/dd[2]/span[last()]/text()")[0]

  89. #近1年

  90. nearly_1_year =data_of_fund.xpath("./dl[1]/dd[3]/span[last()]/text()")[0]

  91. #日期

  92. date = data_of_fund.xpath("./dl[2]/dt/p/text()")[0]

  93. date = re.findall(r"(\d{4}-\d{2}-\d{2})", date)[0] ifre.findall(r"(\d{4}-\d{2}-\d{2})", date) else ""

  94. #单位净值

  95. unit_net_worth =data_of_fund.xpath("./dl[2]/dd[1]/span[1]/text()")[0]

  96. #日增长率

  97. daily_growth_rate =data_of_fund.xpath("./dl[2]/dd[1]/span[2]/text()")[0]

  98. #近3月

  99. nearly_3_month =data_of_fund.xpath("./dl[2]/dd[2]/span[last()]/text()")[0]

  100. #近3年

  101. nearly_3_year =data_of_fund.xpath("./dl[2]/dd[3]/span[last()]/text()")[0]

  102. #累计净值

  103. accumulated_net =data_of_fund.xpath("./dl[3]/dd[1]/span[1]/text()")[0]

  104. #近6月

  105. nearly_6_month =data_of_fund.xpath("./dl[3]/dd[2]/span[last()]/text()")[0]

  106. #基金成立日

  107. since_established =data_of_fund.xpath("./dl[3]/dd[3]/span[last()]/text()")[0]

  108. #获取基金类型,风险程度,规模等信息所在的上层vid

  109. fund_info_item =page_html.xpath("//div[@class='infoOfFund']")[0]

  110. #获取基金的类型以及风险程度

  111. fund_type = fund_info_item.xpath(".//tr[1]/td[1]/a/text()")[0]

  112. fund_risk =fund_info_item.xpath(".//tr[1]/td[1]/text()")[1].split()[-1].strip()

  113. #获取基金规模

  114. fund_scale =fund_info_item.xpath(".//tr[1]/td[2]/text()")[0].split(":")[-1]

  115. #获取基金经理

  116. fund_manager =fund_info_item.xpath(".//tr[1]/td[3]/a/text()")[0]

  117. #获取基金成立日

  118. establishment_date =fund_info_item.xpath(".//tr[2]/td[1]/text()")[0].split(":")[-1]

  119. #获取管理人

  120. administrator =fund_info_item.xpath(".//tr[2]/td[2]/a/text()")[0]

  121. #获取评级类名

  122. fund_rating_class_name =fund_info_item.xpath(".//tr[2]/td[3]/div/@class")[0]

  123. data_list = []

  124. #将每支基金的详细信息拼接成一个列表,并返回

  125. data_list.append(str(fund_code))

  126. data_list.append(str(fund_name))

  127. data_list.append(str(date))

  128. data_list.append(str(unit_net_worth))

  129. data_list.append(str(accumulated_net))

  130. data_list.append(str(daily_growth_rate))

  131. data_list.append(str(nearly_1_week))

  132. data_list.append(str(nearly_1_month))

  133. data_list.append(str(nearly_3_month))

  134. data_list.append(str(nearly_6_month))

  135. data_list.append(str(nearly_1_year))

  136. data_list.append(str(nearly_3_year))

  137. data_list.append(str(since_established))

  138. #根据评级所在divid的类名判断当前基金是几星

  139. if fund_rating_class_name == 'jjpj1':

  140. data_list.append("一星")

  141. elif fund_rating_class_name == "jjpj2":

  142. data_list.append("二星")

  143. elif fund_rating_class_name == "jjpj3":

  144. data_list.append("三星")

  145. elif fund_rating_class_name == "jjpj4":

  146. data_list.append("四星")

  147. elif fund_rating_class_name == "jjpj5":

  148. data_list.append("五星")

  149. else:

  150. data_list.append("暂无评级")

  151. data_list.append(fund_type + " | " + fund_risk)

  152. data_list.append(str(fund_scale))

  153. data_list.append(str(fund_manager))

  154. data_list.append(str(establishment_date))

  155. data_list.append(str(administrator))

  156. driver.quit() # 关闭浏览器

  157. return data_list

  158. if __name__ == '__main__':

  159. start = time.time()

  160. #基金排行按近6月排行页面url

  161. url ="http://fund.eastmoney.com/data/fundranking.html#tall;c0;r;s6yzf;pn50;ddesc;qsd20200725;qed20210725;qdii;zq;gg;gzbd;gzfs;bbzt;sfbb"

  162. tiantian = Tiantian_spider() # 实例化Tiantian_spider类

  163. #获取每个基金的近1周收益和基金详情链接

  164. #传入参数为排行页面url和要获取数据的总页数

  165. url_list = tiantian.get_every_fund_url(url,4)

  166. #要获取的数据,也作为保存excel的标题

  167. data = [["基金代码", "基金简称", "日期", "单位净值", "累计净值", "日增长率", "近一周", "近1月", "近3月", "近6月", \

  168. "近1年", "近3年", "成立来", "基金评级", "基金类型", "基金规模", "基金经理", "成立日", "管理人"]]

  169. result = []

  170. #multiprocessing.cpu_count():获取cpu核数

  171. #新建一个进程池,最大放cpu核数个进程

  172. pool = multiprocessing.Pool(multiprocessing.cpu_count())

  173. for nearly_1_week, url in url_list:

  174. # pool.apply_async:异步执行,10个任务同时执行

  175. # 通过进程池来执行并发任务

  176. # 进程池会自动找不同个数的进程来执行任务函数run, 将args=(url, nearly_1_week)中的url, nearly_1_week两个参数传入run函数

  177. # .get()表示获取任务函数的返回值,即基金的详细信息

  178. result.append(pool.apply_async(func=run, args=(url,nearly_1_week)).get())

  179. pool.close() # 关闭进程池

  180. pool.join() # 阻塞进程,所有进程池中的任务都执行完毕了,才能继续执行主进程

  181. #将基金列表按基金的近6月收益率倒序排列后加入data

  182. data.extend(sorted(result, key=lambda x:x[9], reverse=True))

  183. save_data(data)

  184. end = time.time()

  185. print("耗时为:%s秒" % (end - start))

本文小练习爬取的数据均为公开数据,并且仅限于技术研究,不给网站造成负担。请大家在练习的时候注意合法合规!

 

总结:

感谢每一个认真阅读我文章的人!!!

作为一位过来人也是希望大家少走一些弯路,如果你不想再体验一次学习时找不到资料,没人解答问题,坚持几天便放弃的感受的话,在这里我给大家分享一些自动化测试的学习资源,希望能给你前进的路上带来帮助。

软件测试面试文档

我们学习必然是为了找到高薪的工作,下面这些面试题是来自阿里、腾讯、字节等一线互联网大厂最新的面试资料,并且有字节大佬给出了权威的解答,刷完这一套面试资料相信大家都能找到满意的工作。

 

          视频文档获取方式:
这份文档和视频资料,对于想从事【软件测试】的朋友来说应该是最全面最完整的备战仓库,这个仓库也陪伴我走过了最艰难的路程,希望也能帮助到你!以上均可以分享,点下方小卡片即可自行领取。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

物联网设计竞赛_5_Jetson Nano连接摄像头解决运行卡顿问题

我在命令行用camorama命令打开摄像头的时候发现摄像头非常流畅 当我用python的cv2库打开摄像头的时候发现摄像头显示图片异常卡顿&#xff0c;在网上多方寻觅无果后&#xff0c;经过偶然尝试&#xff0c;我发现了卡顿原来是视频帧率问题 淘宝官方资料看我的摄像头只有30fps, …

Gone框架介绍17 - 创建一个可运行在生产环境的Web项目

gone是可以高效开发Web服务的Golang依赖注入框架 github地址&#xff1a;https://github.com/gone-io/gone 文档原地址&#xff1a;https://goner.fun/zh/guide/auto-gen-priest.html 请帮忙在github上点个 ⭐️吧&#xff0c;这对我很重要 &#xff1b;万分感谢&#xff01;&a…

练习队列的相关操作:循环队列

1. 思路解析 循环队列就是在只有有限的空间时使用队列实现循环存储数据&#xff0c;有双向链表和数组两种选择&#xff0c;这里我们使用数组实现循环队列&#xff08;因为链表我不会 >-<&#xff09; 2. 相关函数及其实现 2.1 判空与判满 判空&#xff1a;直接返回头尾…

景源畅信数字:做抖音切片的方法分享?

一提起抖音切片&#xff0c;很多人可能会想到那些让人眼前一亮的短视频。它们通常短小精悍&#xff0c;内容丰富多彩&#xff0c;能够迅速吸引观众的注意力。但是&#xff0c;如何制作出这样的切片视频呢?这就是我们今天要探讨的问题。 一、选材与剪辑 制作抖音切片&#xff0…

每日一日 kotori和气球

kotori和气球 (nowcoder.com) 题目描述&#xff0c;就是只要相邻的气球不相同即可&#xff0c; 解题思路 使用高中的排列组合&#xff1a;第一个位置 可以填n种情况 其次后推不可与前一个相同所以可以 填n -1中情况&#xff0c;结果相乘即可 可以使用bigInteger实现 或者说…

记录计全支付切换到RabbitMQ时启动报错的问题

记录计全支付切换到RabbitMQ时启动报错的问题 首先在application.yml中切换到RabbitMQ配置安装RabbitMQ、Erlang、延时插件 rabbitmq_delayed_message_exchange&#xff0c;延迟插件必装 首先在application.yml中切换到RabbitMQ配置 # 第一处rabbitmq:addresses: 127.0.0.1:56…

微信视频号开店需要多少钱?2024年最新入驻条件,商家必看!

哈喽~我是电商月月 视频号小店逐渐走入大众视野&#xff0c;观众多&#xff0c;但里面的商家却很少&#xff0c;很多想创业做电商的朋友&#xff0c;就把目光锁定到了视频号平台&#xff0c;那现在视频号小店的入驻费用肯定是新手&#xff0c;最关心的事情了&#xff01; 今天…

javaEE进阶——SpringBoot与SpringMVC第一讲

文章目录 什么是springMVCSpringMVC什么是模型、视图、控制器MVC和SpringMVC的关系SpringMVC的使用第一个SpringMVC程序RestController什么是注解 那么RestController到底是干嘛的呢&#xff1f;RequestMapping 如何接收来自请求中的querystryingRequestParamRequestMapping(&q…

Java入门基础学习笔记18——赋值运算符

赋值运算符&#xff1a; 就是“”&#xff0c;就是给变量赋值的&#xff0c;从右边往左边看。 int a 10; // 把数据赋值给左边的变量a存储。 扩展赋值运算符&#xff1a; 注意&#xff1a;扩展的赋值运算符隐含了强制类型转换。 package cn.ensource.operator;public class…

Linux 第三十四章

&#x1f436;博主主页&#xff1a;ᰔᩚ. 一怀明月ꦿ ❤️‍&#x1f525;专栏系列&#xff1a;线性代数&#xff0c;C初学者入门训练&#xff0c;题解C&#xff0c;C的使用文章&#xff0c;「初学」C&#xff0c;linux &#x1f525;座右铭&#xff1a;“不要等到什么都没有了…

svn批量解锁

问题 svn对文件进行checkout之后&#xff0c;先进行lock&#xff0c;之后再去更改&#xff0c;最后进行Commit操作&#xff1b; 上述为我们通过svn管理代码的正常方式&#xff0c;但总会有其他现象发生&#xff1b; 如果我们非正常操作&#xff0c;批量锁所有的svn文件&#x…

中国农业大学:学硕11408复试线上涨40分,今年还会持续涨吗?中国农业大学计算机考研考情分析!

中国农业大学&#xff08;China Agricultural University&#xff09;&#xff0c;简称“中国农大”&#xff0c;坐落于中国首都北京&#xff0c;由中华人民共和国教育部直属&#xff0c;中央直管副部级建制&#xff0c;水利部、农业部和北京市共建&#xff0c;位列国家“双一流…

串,数组和广义表

2.1.求next和nextval的实现 代码&#xff1a; int next_one(char *str, int len) {int result 1;if(len 1 || len 0) return len;for (size_t i 1; i < len; i){ if(compare(str, strlen-i, i)) {result i1;//break;}}return result; }int next(char *str, int *…

【校园生活小程序_超详细部署】

校园生活小程序 1 完整小程序源码2 运行环境3 初次运行3.1 启动后端程序3.1.1 导入项目&#xff0c;找到项目的pom.xml文件&#xff0c;点击ok进行打开。3.1.2 创建数据库并插入内容 3.1.3 配置项目结构信息3.1.4 配置Tomcat服务器3.1.5 正式启动后端项目3.1.6出现BUG3.1.7 解决…

小程序框架是智能融媒体平台构建的最佳线路

过去5年&#xff0c;媒体行业一直都在进行着信息化建设向融媒体平台建设的转变。一些融媒体的建设演变总结如下&#xff1a; 新闻终端的端侧内容矩阵建设&#xff0c;如App新闻端&#xff0c;社交平台上的官方媒体等新闻本地生活双旗舰客户端&#xff0c;兼顾主流媒体核心宣传…

【密评】 | 商用密码应用安全性评估从业人员考核题库(09)

Hill密码是重要古典密码之一&#xff0c;其加密的核心思想的是&#xff08;&#xff09;。 A.线性变换 B.非线性变换 C.循环移位 D.移位 著名的Kerckhoff原则是指&#xff08;&#xff09;。 A.系统的保密性不但依赖于对加密体制或算法的保密&#xff0c;而且依赖于密钥 B.系统…

深入 Go 语言:使用 math/rand 包实现高效随机数生成

深入 Go 语言&#xff1a;使用 math/rand 包实现高效随机数生成 介绍math/rand 包的核心功能设计哲学应用场景 基础使用方法初始化和种子设置设置种子创建私有随机数生成器 基础函数详解生成整数生成特定范围的整数生成浮点数随机置乱数组 进阶技巧随机数的统计属性生成正态分布…

第83天: 代码审计-PHP 项目RCE 安全调试追踪代码执行命令执行

案例一&#xff1a;CNVD拿1day-RCE命令执行-百家CMS 这里用代码审计系统搜索system&#xff0c;可以利用的是第一种 打开看细节 查找函数引用 查找$_file第一次出现的地方 这个时候就明白了&#xff0c;必须上传文件&#xff0c;然后利用文件名&#xff0c;去执行system命令 …

2024年湖北省安全员-B证证模拟考试题库及湖北省安全员-B证理论考试试题

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 2024年湖北省安全员-B证证模拟考试题库及湖北省安全员-B证理论考试试题是由安全生产模拟考试一点通提供&#xff0c;湖北省安全员-B证证模拟考试题库是根据湖北省安全员-B证最新版教材&#xff0c;湖北省安全员-B证大…

有多少小于当前数字的数字

链接&#xff1a;https://leetcode.cn/problems/how-many-numbers-are-smaller-than-the-current-number/description/ 思路&#xff1a; 最简单的思路来说&#xff0c;就是双重for循环进行遍历&#xff0c;来判断个数&#xff0c; 优化思路&#xff0c;其中一个思路就是递推 …