爬虫技能之内容提取:如何从有不可见元素混淆的页面中抽取数据 概述 分析 & 实现 优点 & 缺点

之前在知乎上看到有人分享的一个有趣的反爬策略:

爬虫技能之内容提取:如何从有不可见元素混淆的页面中抽取数据
概述
分析 & 实现
优点 & 缺点

那个变态混淆页面源码是这个样子的,正文内容穿插在混淆元素中:

爬虫技能之内容提取:如何从有不可见元素混淆的页面中抽取数据
概述
分析 & 实现
优点 & 缺点

看到这么变态的页面结构很感兴趣于是就尝试解析了一下。

知乎分享地址:有哪些有趣的反爬虫手段? - 阿阿聪的回答 - 知乎

微信变态混淆页面地址:过年同学聚会,到底该不该去?

分析 & 实现

对于这种一般都是在选择器中过滤掉不可见的元素就可以了,对于不可见元素目前遇到过并解决掉的两种情况:

1. 通过display:none;来隐藏(全网代理公开ip爬取(隐藏元素混淆+端口加密)

2. 通过透明度和偏移来隐藏,比如opacity: 0;虽然元素透明了但是在盒子模型中还是占用了空间的,会把旁边挤开太明显了所以就需要再margin偏移一下将其占用空间释放掉。

实际上两种方式还是有区别的,display:none;的内容复制不会被影响,复制到的是看到的内容,opacity:0; 并偏移的复制的话会把混淆元素的内容也带上,复制到的并不是看到的内容。

这个微信页面就是第二种方式,来看下它的套路:

<span style="margin-right: -1em; max- 100%; opacity: 0; box-sizing: border-box !important; word-wrap: break-word !important;">钔</span>

先通过opacity:0;将自己变成透明的,然后使用margin-right:-1em;将占用的位置腾出来。

思路就是遍历整个DOM树手动过滤收集,下面是一个简单的实现,只是将文本内容抓取没有保存样式和图片:

"""
微信不可见元素混淆页面内容解析
https://mp.weixin.qq.com/s?__biz=MzI0MDYwNjk2OA==&mid=2247484365&idx=4&sn=291a93e8a4ce6e90d3b6ef8b98fe09c4&chksm=e919085ade6e814cc037ecf6a873f22da0e492911a4e539e6f8fdeff022806b4d248c4d54194&scene=4
"""
import requests
import bs4


def get_html(url):
    return requests.get(url).content.decode('UTF-8')


def dfs_extract_text(tag):
    result_content = ''
    for child in tag.contents:
        if type(child) == bs4.NavigableString:
            result_content += child
        elif 'style' not in child.attrs or 'opacity: 0;' not in child.attrs['style']:
            # 过滤掉透明元素,要么没有style属性,要么style属性中不包含透明样式,否则认为是透明元素直接忽视掉
            result_content += dfs_extract_text(child)
    return result_content


def parse(url):
    html_content = get_html(url)
    page = bs4.BeautifulSoup(html_content, 'html.parser')
    content_panel = page.find(id='js_content')
    return dfs_extract_text(content_panel)


if __name__ == '__main__':
    target_url = 'https://mp.weixin.qq.com/s?__biz=MzI0MDYwNjk2OA==&mid=2247484365&idx=4&sn=291a93e8a4ce6e90d3b6ef8b98fe09c4&chksm=e919085ade6e814cc037ecf6a873f22da0e492911a4e539e6f8fdeff022806b4d248c4d54194&scene=4'
    content = parse(target_url)
    print(content)

程序运行结果:

昨晚回来晚了,是因为我去参加了一个同学聚会,回来后已经夜里十一点多了。这个聚会:并没有想象中那么亲近,也没有传说中的那么美好,更没有当年时的那种纯粹。给我整体的感觉就是六个字:人很累,心很悲 !原因有三个:第一个原因: 你念念不忘的过去,别人已经忘得一干二净了。我和一个女同学上学时很要好(也许只是我的以为,她未必这么认为),那时因为学校离家远,中午放学我们都不回家,就在学校里吃点从家里带来的饭菜。多年以来,和她之间在我脑海中最清晰的画面,就是吃过简单凑合的午饭,我们手牵手围着硕大的操场一圈又一圈的走,有时谈笑,有时打闹,有时就那么静静,静静的牵手走着……昨晚,我向她提起了这段对于我来说,最难忘最深刻最眷恋的记忆。她却给了我最具杀伤力最具毁灭性的一个回答:我都忘了!!!瞬间,我再也没有聊下去的欲望,索然无味……第二个原因: 我们都被经历戴上了面具,被现实披上了虚伪,再也没有上学时的纯粹!尽管是高档的饭店,晶亮的酒杯,我却觉得抵不上年少时你用零花钱买给我的一颗两毛钱的雪糕,一份自己笨手笨脚做的生日礼物。聚会里面有一个同学经历非常坎坷(我们都知道),他却笑得没心没肺,我们明白他在坚强面对。如果和一群老同学,都要装,都要扛,都要说自己无所谓,那还有什么时候,什么朋友,能让一个人打开心扉 ? ?莫名的感到悲哀:曾经的感情只能留给曾经,过去的记忆只能住在过去。老同学之间,没有共同的未来 !第三个原因: 我们都还是原来的那个人,却没有了原来的那颗心。漫长的岁月肯定改变了我们的容貌,不过仔细分辨,我们都能认出来彼此,眉眼,笑容,举止,习惯,年少时的记忆总是那么的深刻,那么的不可磨灭。最可怕的事:不是岁月让一个人变胖了,变老了,变得外表不一样了,而是,它改变了一个人是非分明的心,一个人错对分清的心,一个人向善护弱的心!混得好的,高谈阔论,一大群人追捧围绕着;混得不好的,沉默不语,一大群人敷衍冷淡着!上学时的我们,没有层次,没有高低,没有等级之分的,因为我们是处在同一个起跑线的。现在的我们,再不是当初了……别再妄想着:彼此亲密无间,没有距离,别再奢望着:彼此畅所欲言,没有顾忌!我们说着交际的话,喝着应酬的酒,带着应付的笑,却再也走不进彼此的心……如今的同学聚会,聚的只能是一群的人,而不是一众的心了;如今的同学聚会,聚的只能是外放的笑声,而不是内在的心声了;如今的同学聚会,聚的只能是重逢的酒菜飘香,散场后的感触凄凉 !—《END》—

优点 & 缺点

使用这种方式渲染出的页面,当我复制网页内容并粘贴到别处的时候:

爬虫技能之内容提取:如何从有不可见元素混淆的页面中抽取数据
概述
分析 & 实现
优点 & 缺点 

悲剧啊,我复制出来的内容包括了不可见元素的内容,这可以说是一把双刃剑吧,如果作为一个遵纪守法的正常用户我感觉很无辜,为毛我复制到的内容不是我看到的内容呢,这啥破网站啊,这是网站方不希望看到的。但是如果对面的是爬虫的话,一个不小心就会造成这种后果:
爬虫技能之内容提取:如何从有不可见元素混淆的页面中抽取数据
概述
分析 & 实现
优点 & 缺点 

这恐怕是网站方喜闻乐见的…

具有同样特性的还有自定义字体反爬,欲知详情且听下回分析。

.