爬取私募排排网历史净值和破解加密数值(下)

AI悦创

共 4735字,需浏览 10分钟

 · 2021-08-16

阅读本文大概需要6分钟

你好,我是悦创。上一篇:爬取私募排排网历史净值和破解加密数值(上)这篇我们继续。

二、对每个基金处理

经过上一步解析网页之后,得到每个基金的网站。现在循环处理这些网址,爬取数据。

1. 解析每个基金网页

解析每个基金网页还是运用 driver.get 加载网页,利用 page_source 解析网页。

driver.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument", {
"source": """
Object.defineProperty(navigator, 'webdriver', {
get: () => undefined
})
"""

})
for ind in range(len(list_name)):
driver.get(list_url[ind]) # 加载网站

不过在 page_source 解析网页之前,有一个东西必须要注意!

那就是如果直接解析网页得到的历史净值只有一小部分,是因为历史净值是一个动态的,我们在解析之前需要利用selenium将历史净值这个内嵌框下滑到底,而且这个内嵌框是一个异步加载的(滑动完后,又会出来一段),使用需要多个滑动才能满足条件。

image-20210808164026623

解决问题要点:首先得将历史净值点击,然后定位历史净值框。

如图已经定位到了内嵌框,下面就开滑动

driver.find_element(By.XPATH,'//div/div[2]/div[2]/div[1]/div[2]/div[1]/div[1]/a[2]').click()        # 点击历史净值

for i in range(50):
js = 'document.getElementsByClassName("tbody")[0].scrollTop=100000' # 在历史净值中滑动,这里滑动50应该是都够了的,如果不够加大就行
driver.execute_script(js)
time.sleep(0.1) # 防止滑动太快,没有读取到结果

page_url = driver.page_source # 解析当前网页

注意 getElementsByClassName("tbody")[0] 这里是查找属性class的属性值为 tbody ,中的第一个元素(一定要带上后面这个 0,因为返回的是一个集合。如果滑动的是 4 个元素就是后面就是 3)

下面就是定位 docment 对象的方法,和 css 定位一样。

image-20210808190751925

感兴趣可以看看 JavaScript 学习链接 http://www.runoob.com/jsref/dom-obj-document.html

2. 解密历史净值中的隐藏值

(1)隐藏值原理

经过上一步就得到了每个基金的网页,接下来就来开始解密。

在解密前我们先来看看它是怎么加密的吧!

可以看到在 html 中存在着网页中没有的内容,这个就是加密。

说实话,在这里花费了不少的时间。我先来说说我的思路吧。

  1. 找规律

    在开始尝试找规律,最开始规律就是每个值中的span一定是有用的,但是后来发现有的没有span,然后,然后就没有然后了,直接放弃这种想法了。

  2. css 偏移

    然后就是 css 偏移就是利用 css 样式将网页中正常的值乱序。但是发现我们这里的值顺序是正常的,只是多了部分值,所以页排除这种想法。

  3. 存在隐藏值,最后发现了规律,存在的值(网页上显示的值)

    image-20210808200015651

    不存在的值(网页上不显示的值)

    image-20210808200204943

会发现网页上面不存在的值多了 font: 0/0 a 这个值。

image-20210808201653244

当把 font: 0/0 a 这个边框不勾选了,就会发现网页中会有很多的值中间是有空格的,那么可以得出结论 html中多出来的值并不是多余的,它也是存在网页中的,但是它被隐藏了。

然后我们就抓住在这个特点继续找下去。

当我们发现 ENCODE_STYLE 对应的内容就是和找到的规律一样。

image-20210808201017372
.m440e0{font: 0/0 a;color: transparent;text-shadow: none;background-color: transparent;border: 0;}.m446e7{font: 0/0 a;color: transparent;text-shadow: none;background-color: transparent;border: 0;}.m48eb7{text-shadow: none;background-color: transparent;border: 0;}.m45029{text-shadow: none;background-color: transparent;border: 0;}.m41fd7{font: 0/0 a;color: transparent;text-shadow: none;background-color: transparent;border: 0;}.m4dec4{text-shadow: none;background-color: transparent;border: 0;}.m44109{text-shadow: none;background-color: transparent;border: 0;}

可以去验证,以 m440e0 为属性值去找元素,可以发现全是隐藏值。同理,m48eb7 为属性值去找元素全是真实值。

结论:html中多出来的值并不是多余的,它也是存在网页中的,但是它被隐藏了。这些隐藏值以及真实值在ENCODE_STYLE属性中。所以只需要在ENCODE_STYLE中找存在font: 0/0 a的属性值,即为隐藏值。

(2)代码实现

# 找到隐藏的属性值
def getHideIds(htmlEtree):
encode_styles = "".join(htmlEtree.xpath('//div[@id="ENCODE_STYLE"]/style/text()')).replace("\n", "")
# 清洗数据,去除连续的空格
new_encode_styles = re.sub(" +", "", encode_styles)
# 获取全部被隐藏的id
hideIds1 = re.findall("\.(\w+) {font: 0/0 a;", new_encode_styles) # 格式化后的html
hideIds2 = re.findall("\.(\w+){font: 0/0 a;", new_encode_styles) # 未格式化的html
result = set(hideIds1 + hideIds2)
return result

定义一个函数,调用 xpath 解析的 page_source,返回值为隐藏值的属性值。即类似于 m440e0,m41fd7 的值。

然后只需要将隐藏值对应的元素找出来就行了。

htmlEtree = etree.HTML(text=htmlData)

# 获取被隐藏的id
hideIds = getHideIds(htmlEtree)

# 处理数据
divList = htmlEtree.xpath('//div[@class="tr flex-h-center"]')
# print(divList)
tdDivs = []
for div in divList:
nextDivs = div.xpath('./div[@class="td flex-h-center"]')
for nextDiv in nextDivs:
if nextDivs.index(nextDiv) == 0:
continue
tdDivs.append(nextDiv)

resultList = []
for tdDiv in tdDivs:

labels = tdDiv.xpath("./*")
nowResultList = []
for label in labels:
classStr = label.xpath("./@class")[0]
if classStr not in hideIds:
nowResultList.append(label.xpath("./text()")[0])
resultList.append("".join(nowResultList))

# print(resultList)
# for reslut in resultList:
# print(reslut)

三、将所有数据写入excel

最后再将净值日期和净值变动找到(这两个没有掺杂隐藏值,很简单就能找到),然后利用pandas写入excel中。

write = pandas.ExcelWriter(r"C:\Users\86178\Desktop\私募排排网历史净值爬取.xlsx")   # 新建xlsx文件。
list_info.append([list_date[index], resultList[i], resultList[i + 1], resultList[i + 2], list_net[index]]) # 分别对应净值日期,单位净值,累计净值,累计净值,净值变动

pd = pandas.DataFrame(list_info, columns=['净值日期', '单位净值', '累计净值(分红再投资)', '累计净值(分红不投资)', '净值变动'])
# print(pd)
pd.to_excel(write, sheet_name=list_name[ind], index=False)

write.save() # 这里一定要保存

最后得到结果

四、总结

本文主要是讲的selenium的一些基本操作,例如鼠标事件、键盘事件和鼠标悬停。然后就是解密隐藏值。

我在这里遇见了很多的坑,思考了一个下午才把思路想到。我很庆幸在我最艰难的时候,没有说放弃,其实这次更大的收获是让自己对爬虫有更加深刻的见解。

AI悦创·推出辅导班啦,包括「Python 语言辅导班、C++辅导班、算法/数据结构辅导班、少儿编程、pygame 游戏开发」,全部都是一对一教学:一对一辅导 + 一对一答疑 + 布置作业 + 项目实践等。QQ、微信在线,随时响应!V:Jiabcdefh

作者:AI悦创
排版:AI悦创





黄家宝丨AI悦创

隐形字

摄影公众号「悦创摄影研习社」


在这里分享自己的一些经验、想法和见解。


长按识别二维码关注




好文和朋友一起看~
浏览 20
点赞
评论
收藏
分享

手机扫一扫分享

举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

举报