Python爬虫实战N04CSS伪元素反爬图文教程

2024-12-24阅读数:37
上一篇:Python爬虫实战N05CSS Sprites (雪碧图)反爬图文教程
下一篇:Python爬虫实战H06初识浏览器指纹:Selenium是如何被反爬的图文教程

打开Python爬虫实战练习页面CSS伪元素反爬_N04_Spiderbuf,可以看到页面内容是豆瓣电影评分。

在网页上点击右键 > 显示网页源代码,可以看到网页结构也并不复杂。往下滚动查看源码,第115行开始是豆瓣电影内容介绍及评分。

第115行HTML源码找到了9.3这样的数字,看起来是电影评分,但回到页面上看,实际上看到的是9.7这样的内容。很明显HTML源码里的内容是用来误导爬虫的。

<span>豆瓣电影评分:</span><span class="mnopqr pkenmc">.</span><span class="rbmsak">9.3</span><br />

从源码来看,有一个 rbmsak 这样的CSS类包裹了起来,我们就搜索 rbmsak 找到这个样式。在源码第442行找到了这个样式的定义代码,发现它只是定义了一个字体颜色。

.rbmsak {
    color: #141d2b;
}

回到页面内容,通过浏览器开发者工具(F12)选中元素的功能选中第一个电影信息的豆瓣评分这里,就能发现这个rbmsak 样式把9.3这个值通过设置成网页背景颜色的方式隐藏了,也就是说我们在网页上看到的真实的值不是这个。但是我们在开发者工具 -> 元素这里能看来如下的代码:

开发者工具元素代码

注意其中的 before 及 after 代码,结合CSS相关知识可知,这里是由CSS进行了赋值。通常关键字搜索上面代码中出现的类名 mnopqr ,找到以下CSS样式代码:

.mnopqr::before {
    content: "9";
}

.mnopqr::after {
    content: "1";
}

这里明显就是CSS赋值到html的代码,而且可以发现这样的定义代码还有一长串。CSS before 及 after 是把 content 里面的内容赋值到html里面的,换句话来说,我们只要从html中取到类名,并找出对应类名中的 content 的内容就可以把真实的内容爬取下来。根据这个思路,我们先用Python代码构造一下字典:

class_map = {'abcdef::before':'7',
        'abcdef::after':'5',
        'ghijkl::before':'8',
        'ghijkl::after':'9',
        'mnopqr::before':'9',
        'mnopqr::after':'1',
        'uvwxyz::before':'1',
        'uvwxyz::after':'4',
        'yzabcd::before':'2',
        'yzabcd::after':'6',
        'efghij::before':'3',
        'efghij::after':'2',
        'klmnop::before':'5',
        'klmnop::after':'7',
        'qrstuv::before':'4',
        'qrstuv::after':'3',
        'wxyzab::before':'6',
        'wxyzab::after':'0',
        'cdefgh::before':'0',
        'cdefgh::after':'8',
        'hijklm::after':'6',
        'opqrst::after':'0',
        'uvwxab::after':'3',
        'cdijkl::after':'8',
        'pqrmno::after':'1',
        'stuvwx::after':'4',
        'pkenmc::after':'7',
        'tcwdsk::after':'9',
        'mkrtyu::after':'5',
        'umdrtk::after':'2'}

字典的键是完整的CSS类名,字典的值是CSS类定义代码中 content 中的内容,我们就可以通过类名转换获取到对应的值。

attr_class = span.attrib['class'] if 'class' in span.attrib else ''
classes = attr_class.split(' ')
if len(classes) > 0:
        s1 = class_map[classes[0] + '::before']
        s2 = class_map[classes[1] + '::after']
        print(f'{s1}.{s2}')

这样我们就完成了豆瓣电影评分值的爬取。

至于页面中的其它内容,没有特别的反爬措施,只需要获取到对应的xpath表达式然后提取内容即可。

完整示例代码:示例代码