爬虫应对反爬之css反爬

时间:2024-03-08 13:21:53
最近看到一个网站有css反爬,感觉比较有意思,这里就顺手**一下,纯做技术分享

首先打开它的站点,感觉是个很low又没有任何反爬的站点,它长这样:
img1
很单纯的列表页,此页面无任何反爬,直接分析拿到详情页的地址即可。有意思的来了…

任意打开一篇详情页文章
img2
可以看到它是一个字一个字的显示的,而有的字是不显示的,通过css障眼法隐掉不显示的字,剩下的就是完整的内容啦。
可以看到这些字只有一个class属性,那么这些字显不显示就应该是通过这个属性控制的了。

我们观察一下正常的文字有什么css属性
img3
再观察一下干扰(不显示的)文字有啥css属性
img4
可以发现不显示的文字都有一个float: left的css属性。通过多观察几个,你就发现,凡是带这个float:left属性就是不显示的文字,那在后面的文字提取中去掉带这个属性的即可。

找到它的外部的css
img5
点击进去
img6
观察一下,我们需要提取这个页面中带overflow:hidden、同时不带float:left的class名。然后我们就可以根据class属性提取文字了。
先不急着写代码,通过多点击几个详情页,你会发现,这个外部引用的css文件不是固定的,也就是说,你先提取文字的时候,每次要先把它显示的class名先从这个外部的css文件中提取出来。

因为css在详情页中才能找到
img7
所以必须先请求详情页,拿到css,提取显示文字的class属性,在解析完css再解析详情页内容
提取字的时候也要注意一些问题,比如它的标点符号是没有任何属性的,提取也有点麻烦.
最难的部分搞定了,下面贴代码(Scrapy的爬虫文件)

# -*- coding: utf-8 -*-
import scrapy
import re

class Qiwen007Spider(scrapy.Spider):
    name = \'qiwen007\'
    start_urls = [\'http://m.qiwen007.com/\']
    
    def parse(self, response):
        a_lists = response.xpath("//div[@class=\'bt\']/a")
        for a in a_lists:
            title = a.xpath("./text()").extract_first()
            item = dict()
            url = a.xpath("./@href").extract_first()
            item["title"] = title
            item["url"] = response.urljoin(url)
            item["imageAddr"] = []
            item["content"] = ""
            yield scrapy.Request(response.urljoin(url), callback=self.detail, meta={"item": item})

    def detail(self, response):
        item = response.meta["item"]
        css = response.xpath("//head/link[@type=\'text/css\']/@href").extract()
        html = response.text
        css_url = "http://m.qiwen007.com" + css[1]
        yield scrapy.Request(css_url, callback=self.handler, meta={"html": html, "item": item}, dont_filter=True)

    def handler(self, response):
        item = response.meta["item"]
        ss = response.text.split("\n")
        ss = {i.split("{")[0].lstrip(".") for i in ss if "overflow:hidden" in i and "float:left" not in i}
        html = response.meta["html"]
        res = scrapy.Selector(text=html)
        elements = res.xpath("//div[@id=\'textbody\']//p | //div[@id=\'textbody\']/div[@class=\'picimg\']/img")
        contents = item["content"]
        for element in elements:
            if element.root.tag == "p":
                text = element.extract()
                result = re.findall(r\'class="(.*?)">(.*?)<\', text, flags=re.S)
                for i in result:
                    if i[0] not in ss:  # 根据属性剔除不显示的干扰文字
                        text = text.replace(\'<dfn class="{}">{}</dfn>\'.format(i[0], i[1]), "")
                # 找出所有汉字
                kk = re.findall(r">(.*?)<", text, flags=re.S)
                contents += "<p>{}</p>".format("".join(kk))
            else:
                src = element.xpath("./@src").extract_first()
                src = response.urljoin(src)
                img = "<img src=\'{}\'>".format(src)
                contents += img
                item["imageAddr"].append(src)
        item["content"] = contents
        # 找出下一页,匹配所有文章
        next_page = res.xpath("//a[@id=\'NY_XYY\']/@href").extract_first()
        if next_page:
            next_page = response.urljoin(next_page)
            yield scrapy.Request(next_page, callback=self.detail, meta={"item": item})
        else:
            yield item