实战+代码!Selenium + Phantom JS爬取天天基金数据
功能:
通过程序实现从基金列表页,获取指定页数内所有基金的近一周收益率以及每支基金的详情页链接。再进入每支基金的详情页获取其余的基金信息,将所有获取到的基金详细信息按近6月收益率倒序排列写入一个Excel表格。
思路:
-
通过实例化Tiantian_spider类的对象,初始化一个PhantomJS浏览器对象
-
使用浏览器对象访问天天基金近六月排行的页面,获取该页面的源码
-
从源码从获取每支基金所在的行(可以指定要获取基金的页数)

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

-
获取到每个基金的详情链接后,使用多进程分别进入每支基金的详情页面
-
进入详情页后,获取基金的相关信息,并存入列表

-
将从所有基金的基金详情与在列表页获取的基金近1周收益率拼接后存入列表
-
再将所有信息写入Excel表格

from selenium import webdriver
from lxml import etree
import time
from openpyxl import Workbook
import multiprocessing
import reclass Tiantian_spider():def __init__(self):self.driver = webdriver.PhantomJS() #指定的PhantomJS浏览器创建浏览器对象self.html = Noneself.next_page = Trueself.fund_url_list = []#1 发起请求def parser_url(self):# if self.next_page :# 点击页面进行翻页# label[last()]---》定位到最后一个label,即# last()是一个函数,表示取最后一个self.driver.find_element_by_xpath("//div[@id='pagebar']/label[last()]").click()time.sleep(4) # 网页返回数据需要时间self.html = self.driver.page_sourcedef parser_data_for_url(self):'''从基金列表页获取每支基金的近一周收益和详情链接'''# 解析字符串格式的HTML文档对象,将传进去的字符串转变成_Element对象
html = etree.HTML(self.html)tr_list = html.xpath("//table[@id ='dbtable']//tbody/tr")next_page = html.xpath("//div[@id ='pagebar']//label[last()]")for tr in tr_list:tds =tr.xpath("./td")# 将近一周收益和详情链接组成的元组加入fund_url_list列表self.fund_url_list.append((str(tds[8].text),str(tds[2].xpath("./a/@href")[0])))return next_page # 返回下一页#翻页控制器def over_page(self,next_page):# 获取最后一页kw = next_page[0].xpath("./label[contains(@class,'end')]")# print(kw)# 判断是否是最后一页,如果是,则返回False,否则返回Trueflag = True if len(kw)==0 else Falsereturn flagdef get_every_fund_url(self, url, page):# page:要获取前多少页的基金数据# 1 发起请求# 2 获取数据,解析数据self.driver.get(url)self.html = self.driver.page_source# 当页数不为0且还有下一页时,执行下面的操作while page > 0 and self.next_page:next_page= self.parser_data_for_url()# 4 翻页继续爬取self.next_page = self.over_page(next_page)# 如果不是下一页,就继续翻页if self.next_page:self.parser_url()page -= 1# 返回每支基金近一周收益和详情链接return self.fund_url_listdef close_driver(self):self.driver.quit()def save_data(data):wb = Workbook() # 新创建一个文件ws = wb.active # 获取当前正在运行的工作表/激活工作表#将数据一行一行插入到工作表中#列表第一个元素将作为标题for i in data:ws.append(i)wb.save("近6月基金排名_" + time.strftime('%Y%m%d%H%M%S')+".xlsx")# 多进程任务函数
# 获取进入基金的详情页获取详细信息
def run(url, nearly_1_week):driver = webdriver.PhantomJS()driver.get(url) page_html = etree.HTML(driver.page_source) # 获取页面源码#获取基金名称#通过xpath或者的是一个元素列表,要元素下面的子元素,需要取某个具体的元素,不能用列表取fund_name =page_html.xpath("//div[@class='fundDetail-tit']/div/text()")[0]#获取基金代码类名fund_code_class_name = page_html.xpath("//div[@class='fundDetail-tit']/div/span[last()]/@class")[0]#根据代码类名判断基金代码只有一个,还是有前后端两个if fund_code_class_name == "ui-num":fund_code = page_html.xpath("//div[@class='fundDetail-tit']/div/span[last()]/text()")[0]elif fund_code_class_name == "fundcodeInfo":fund_code_info = page_html.xpath("//div[@class='fundDetail-tit']/div/span[@class='fundcodeInfo']")[0]fund_code = "前端: " +fund_code_info.xpath("./span[1]/text()")[0] + " 后端: " + fund_code_info.xpath("./span[2]/text()")[0]#收益和净值所在的上层divdata_of_fund = page_html.xpath("//div[@class='dataOfFund']")[0]#近1月nearly_1_month =data_of_fund.xpath("./dl[1]/dd[2]/span[last()]/text()")[0]#近1年nearly_1_year =data_of_fund.xpath("./dl[1]/dd[3]/span[last()]/text()")[0]#日期date = data_of_fund.xpath("./dl[2]/dt/p/text()")[0]date = re.findall(r"(\d{4}-\d{2}-\d{2})", date)[0] ifre.findall(r"(\d{4}-\d{2}-\d{2})", date) else ""#单位净值unit_net_worth =data_of_fund.xpath("./dl[2]/dd[1]/span[1]/text()")[0]#日增长率daily_growth_rate =data_of_fund.xpath("./dl[2]/dd[1]/span[2]/text()")[0]#近3月nearly_3_month =data_of_fund.xpath("./dl[2]/dd[2]/span[last()]/text()")[0]#近3年nearly_3_year =data_of_fund.xpath("./dl[2]/dd[3]/span[last()]/text()")[0]#累计净值accumulated_net =data_of_fund.xpath("./dl[3]/dd[1]/span[1]/text()")[0]#近6月nearly_6_month =data_of_fund.xpath("./dl[3]/dd[2]/span[last()]/text()")[0]#基金成立日since_established =data_of_fund.xpath("./dl[3]/dd[3]/span[last()]/text()")[0]#获取基金类型,风险程度,规模等信息所在的上层vidfund_info_item =page_html.xpath("//div[@class='infoOfFund']")[0]#获取基金的类型以及风险程度fund_type = fund_info_item.xpath(".//tr[1]/td[1]/a/text()")[0]fund_risk =fund_info_item.xpath(".//tr[1]/td[1]/text()")[1].split()[-1].strip()#获取基金规模fund_scale =fund_info_item.xpath(".//tr[1]/td[2]/text()")[0].split(":")[-1]#获取基金经理fund_manager =fund_info_item.xpath(".//tr[1]/td[3]/a/text()")[0]#获取基金成立日establishment_date =fund_info_item.xpath(".//tr[2]/td[1]/text()")[0].split(":")[-1]#获取管理人administrator =fund_info_item.xpath(".//tr[2]/td[2]/a/text()")[0]#获取评级类名fund_rating_class_name =fund_info_item.xpath(".//tr[2]/td[3]/div/@class")[0]data_list = []#将每支基金的详细信息拼接成一个列表,并返回data_list.append(str(fund_code))data_list.append(str(fund_name))data_list.append(str(date))data_list.append(str(unit_net_worth))data_list.append(str(accumulated_net))data_list.append(str(daily_growth_rate))data_list.append(str(nearly_1_week))data_list.append(str(nearly_1_month))data_list.append(str(nearly_3_month))data_list.append(str(nearly_6_month))data_list.append(str(nearly_1_year))data_list.append(str(nearly_3_year))data_list.append(str(since_established))#根据评级所在divid的类名判断当前基金是几星if fund_rating_class_name == 'jjpj1':data_list.append("一星")elif fund_rating_class_name == "jjpj2":data_list.append("二星")elif fund_rating_class_name == "jjpj3":data_list.append("三星")elif fund_rating_class_name == "jjpj4":data_list.append("四星")elif fund_rating_class_name == "jjpj5":data_list.append("五星")else:data_list.append("暂无评级")data_list.append(fund_type + " | " + fund_risk)data_list.append(str(fund_scale))data_list.append(str(fund_manager))data_list.append(str(establishment_date))data_list.append(str(administrator))driver.quit() # 关闭浏览器return data_list if __name__ == '__main__':start = time.time()#基金排行按近6月排行页面urlurl ="http://fund.eastmoney.com/data/fundranking.html#tall;c0;r;s6yzf;pn50;ddesc;qsd20200725;qed20210725;qdii;zq;gg;gzbd;gzfs;bbzt;sfbb"tiantian = Tiantian_spider() # 实例化Tiantian_spider类#获取每个基金的近1周收益和基金详情链接#传入参数为排行页面url和要获取数据的总页数url_list = tiantian.get_every_fund_url(url,4)#要获取的数据,也作为保存excel的标题data = [["基金代码", "基金简称", "日期", "单位净值", "累计净值", "日增长率", "近一周", "近1月", "近3月", "近6月", \"近1年", "近3年", "成立来", "基金评级", "基金类型", "基金规模", "基金经理", "成立日", "管理人"]]result = []#multiprocessing.cpu_count():获取cpu核数#新建一个进程池,最大放cpu核数个进程pool = multiprocessing.Pool(multiprocessing.cpu_count())for nearly_1_week, url in url_list:# pool.apply_async:异步执行,10个任务同时执行# 通过进程池来执行并发任务# 进程池会自动找不同个数的进程来执行任务函数run, 将args=(url, nearly_1_week)中的url, nearly_1_week两个参数传入run函数# .get()表示获取任务函数的返回值,即基金的详细信息result.append(pool.apply_async(func=run, args=(url,nearly_1_week)).get())pool.close() # 关闭进程池pool.join() # 阻塞进程,所有进程池中的任务都执行完毕了,才能继续执行主进程#将基金列表按基金的近6月收益率倒序排列后加入datadata.extend(sorted(result, key=lambda x:x[9], reverse=True)) save_data(data)end = time.time()print("耗时为:%s秒" % (end - start))
如果你不想一个人野蛮生长,找不到系统的资料,问题得不到帮助,坚持几天便放弃的感受的话,可以加入我们的QQ群:746506216,大家可以一起讨论交流,里面会有各种软件测试资料和技术交流。
资源分享
下方这份完整的软件测试视频学习教程已经上传CSDN官方认证的二维码,朋友们如果需要可以自行免费领取 【保证100%免费】


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
