最近看到一个网站有css反爬,感觉比较有意思,这里就顺手破解一下,纯做技术分享
首先打开它的站点,感觉是个很low又没有任何反爬的站点,它长这样:
很单纯的列表页,此页面无任何反爬,直接分析拿到详情页的地址即可。有意思的来了…
任意打开一篇详情页文章
可以看到它是一个字一个字的显示的,而有的字是不显示的,通过css障眼法隐掉不显示的字,剩下的就是完整的内容啦。
可以看到这些字只有一个class属性,那么这些字显不显示就应该是通过这个属性控制的了。
我们观察一下正常的文字有什么css属性
再观察一下干扰(不显示的)文字有啥css属性
可以发现不显示的文字都有一个float: left的css属性。通过多观察几个,你就发现,凡是带这个float:left属性就是不显示的文字,那在后面的文字提取中去掉带这个属性的即可。
找到它的外部的css
点击进去
观察一下,我们需要提取这个页面中带overflow:hidden、同时不带float:left的class名。然后我们就可以根据class属性提取文字了。
先不急着写代码,通过多点击几个详情页,你会发现,这个外部引用的css文件不是固定的,也就是说,你先提取文字的时候,每次要先把它显示的class名先从这个外部的css文件中提取出来。
因为css在详情页中才能找到
所以必须先请求详情页,拿到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