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

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

 

总结:

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

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

软件测试面试文档

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

 

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

  • 4
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值