实战+代码!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))

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

 

总结:

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

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

软件测试面试文档

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

 

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

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

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

相关文章

fastadmin对登录token的处理

fastadmin对token的操作 最近开发遇到一个场景&#xff0c;需要绕过验证获取登录&#xff0c;所以恶补了一下这个知识点&#xff0c;这个主要就是控制fastadmin的token的问题 代码分步实现 class Xcxuser extends Api {//关于鉴权protected $noNeedLogin [login,getopenid,…

错误: 找不到或无法加载主类问题(已解决)

今天在虚拟机中安装了idea2023.2的版本&#xff0c;运行代码时发现错误找不到主类&#xff01; 直接说结论&#xff1a; 我先clean了一下target&#xff0c;然后重新build&#xff0c;发现maven报错了&#xff0c;idea2023.2默认使用了内置的maven&#xff0c;然后我切换了一下…

Yalmip使用教程(8)-常见报错及调试方法

博客中所有内容均来源于自己学习过程中积累的经验以及对yalmip官方文档的翻译&#xff1a;https://yalmip.github.io/tutorials/ 这篇博客将详细介绍使用yalmip工具箱编程过程中的常见错误和相应的解决办法。 1.optimize的输出参数 众所周知&#xff0c;optimize是yalmip用来求…

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

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

解决kali Linux2024无法获取动态IPv4地址(DHCP)解决方案

用root用户启动终端 进入根目录&#xff0c;选择配置文件 cd到根目录下/../etc/network找到interfaces文件 编辑interfaces文件 vi interfaces&#xff0c;编辑interfaces文件 输入如下命令 打开虚拟网络编辑器 选择虚拟机选项卡&#xff0c;编辑&#xff0c;打开虚拟网络编…

Jmeter(四十一) - 从入门到精通进阶篇 - Jmeter配置文件的刨根问底 - 下篇(详解教程)

宏哥微信粉丝群&#xff1a;https://bbs.csdn.net/topics/618423372 有兴趣的可以扫码加入 1.简介 为什么宏哥要对Jmeter的配置文件进行一下讲解了&#xff0c;因为有的童鞋或者小伙伴在测试中遇到一些需要修改配置文件的问题不是很清楚也不是很懂&#xff0c;就算修改了也是…

tag-字符串:最长公共前缀

题目 编写一个函数来查找字符串数组中的最长公共前缀。 如果不存在公共前缀&#xff0c;返回空字符串 “”。 示例 题解一 class Solution:def longestCommonPrefix(self, strs: List[str]) -> str:# 按照字典顺序找到strs中最大的字符串和最小的字符串str0 min(strs)st…

51单片机超声波测距_液位检测_温度检测原理图PCB仿真代码

目录 实物图&#xff1a; PCB ​原理图​ 仿真图 ​编辑 程序 资料下载地址&#xff1a;51单片机超声波测距-液位检测-温度检测原理图PCB仿真代码 主控为stc89c52,通过ds18b20进行温度采集&#xff0c;超声波测距&#xff0c;距离不可以超过1m&#xff0c;通过按键可以设…

Java面试八股之List、Set、Map和Queue之间的区别

Java中List、Set、Map和Queue之间的区别 List List 是一个有序且允许重复元素的集合。它提供了按索引访问元素的能力&#xff0c;也就是说&#xff0c;你可以通过元素的插入位置或指定的索引来精确地访问、添加或删除元素。List 的典型实现包括 ArrayList 和 LinkedList。 特…

喜茶·茶坊黑金首店入驻北京三里屯,率先引入珍稀娟姗奶制茶

发布 | 大力财经 近日&#xff0c;喜茶茶坊 BLACK 在北京三里屯开业&#xff0c;这是喜茶新业态的首家黑金店型。该店在延续喜茶茶坊“鲜、茶、纯”的精品茗茶特色和宋代茶文化审美意趣的基础上&#xff0c;首次升级呈现了铜锅手煮烹茶工艺、娟姗牛乳制茶等创新尝试&#xff0…

【C++ 高阶数据结构 Test】AVL ~ 二叉搜索树

文章目录 1. AVL 树概念2. AVL 树节点的定义3. AVL树的插入4. AVL树的旋转4.1 新节点插入较高左子树的左侧---左左&#xff1a;右单旋4.2 新节点插入较高右子树的右侧---右右&#xff1a;左单旋4.3 新节点插入较高左子树的右侧---左右&#xff1a;先左单旋再右单旋4.4 新节点插…

电工能混到这份上

最近看到某电工师傅发了一篇帖子&#xff0c;大致内容是他在处理一个简单故障的时候居然花了很长的时间。我们一起来看看他遇到的是什么故障吧! plc 控制的一台设备&#xff0c;行走部分靠 2 个脚踏开关控制&#xff08;内部开关量控制方向&#xff0c;电位器控制速度&#xff…