天眼连接你我
0.前言1.字体映射2.动态kg3.作者的话
0.前言
最近读者想让我多发点爬虫文章,实在是时间原因,让各位就等了,我一口气,继续研究字体反爬策略,本文是基于天眼进行初探,后文待续。
今天的目标很简单,复习昨日的猫眼反爬虫策略,并且加以实战运用 ,针对不同情形如何处理,以及最最重要的:我发现了我研究的知识图谱领域的应用场景,看下面的一张图:
没错,这就是我研究的知识图谱,简称KG,之前发过一篇文章用d3可视化,我查看了这个网站,也是用的d3,哈哈,是不是之前的d3用到了呢!
时间总是给有准备的人,好像不对,机会总给有准备的人,如果你掌握了,是不是会更加主动呢?
总结一下需求:第一:字体反爬;第二:kg数据;
那么我们来开张,实战吧!
1.字体映射
思路
这个网站据说很难爬,而且IP会封杀的有点厉害,所以我自己搞了个IP池,去爬,一定不要裸奔!
昨天我们知道字体不是一一对应关系的,那么对于今天的你会发现,是一一映射的(为什么,看后面),那么我们先来看一下网站实际访问的情形:
看上面两个图,发现不匹配啊!这就是该网站使用自定义字体通过映射出来的表现,我们需要得到映射关系,进而反爬获取真实字体。
接下来我们该怎么解决呢,肯定是找字体相关文件,在html中是css中自定义字体或者直接写进网页,那么我们通过筛选出css信息或者直接查看网页源码来找到相应的字体文件,但是源码不好找啊,这里我就用了css筛选法。
看到没,有一个font.css,我们发现woff格式字体链接了,我们只需要把他下载下来即可,这里可以手动复制链接,直接下载,或者使用我下面给出的代码,自动化下载!
有人会问上述那么多链接,选择哪个,这里就在看一下font筛选,看到对应的字体文件,就可以确定下载哪个链接了!
然后打开
http://fontstore.baidu.com/static/editor/index.html
导入woff字体,查看映射关系。
我们看到有汉字。。发现了没,这个网站的反爬虫贼强!我们只是初探!
网页刷新几次会发现字体链接,所以确定是一一映射关系!这里我们将0到9进行一一对应映射。
接下来,让我们畅游代码世界!
实现
【封装】
代码语言:javascript复制class tianyan_Spider():
def __init__(self):
headers = {
'User-Agent': '填入你的浏览器User-Agent',
}
self.headers = headers
以下的所有代码都是基于这个类的封装!
【代理池】
下面是哪IP跟端口去构造代理,最终形式为:
{'http': 'http://95.130.38.4:32920'}
def get_proxy(self):
li_proxy = ["43.242.242.176:43203","158.174.63.117:55535","95.170.157.97:30077","91.214.140.15:32231","94.243.140.162:40960","95.130.38.4:32920"]
proxy_all = []
for i in li_proxy:
dict_proxy = {}
dict_proxy['http']='http://' i
proxy_all.append(dict_proxy)
# {'http': 'http://95.130.38.4:32920'}
print(proxy_all)
return proxy_all
【获取html】
这里要说明一下,我在raw_html
处直接是get一下,没有继续获取text或者content内容,原因在于,为了后面重复使用这个方法,使得逻辑的严谨性跟封装性更好!
def get_html(self,url):
proxy = self.get_proxy()
proxy_len = len(proxy)
for i in range(proxy_len):
t = random.randint(0, proxy_len- 1)
raw_html = requests.get(url, headers=self.headers,proxies=proxy[t])
# 判断IP能不能用
if not raw_html.content:
continue
print("正在使用IP:" str(proxy[t]))
return raw_html
【下载字体】
注意:一定要用content不能用text,content返回bytes,写入以wb正常,如果为text,则报错!
代码语言:javascript复制def save_font(self,url):
font = self.get_html(url).content
with open('./tianyan.woff',"wb") as f:
f.write(font)
【映射关系】
这里自己写的一个算法,用来将字符替换掉,如果各位大佬有更优的算法,欢迎讨论!
算法思路是定义新字符串,如果这个字符出现在关系字典中,则用value替换掉,并放入新字符串中,如果当前这个字符没出现在关系字典中,则说明不需要转换,直接放入新字符就可以。
代码语言:javascript复制def replace_Str(self,raw_str):
rel_dict = {
"0":"0","3":"1","4":"2","9":"3","6":"4",
"2":"5","1":"6","8":"7","7":"8","5":"9",
}
newstr = ""
for i in raw_str:
if i in rel_dict:
newstr =i.replace(i,rel_dict[i])
else:
newstr =i
return newstr
【替换内容】
将非正常内容通过上述算法替换掉即可!
代码语言:javascript复制def get_Content(self,url):
raw_html = self.get_html(url).text
selector = etree.HTML(raw_html)
regist_money = selector.xpath('//div[@id="_container_baseInfo"]/table[1]/tbody/tr[1]/td[2]/div[1]/text()')[0]
print(regist_money)
regist_content = selector.xpath('//div[@id="_container_baseInfo"]/table[1]/tbody/tr[1]/td[2]/div[2]/text/text()')[0]
regist_content = self.replace_Str(regist_content)
print(regist_content)
regist_time = selector.xpath('//div[@id="_container_baseInfo"]/table[1]/tbody/tr[2]/td/div[1]/text()')[0]
print(regist_time)
regist_time_content = selector.xpath('//div[@id="_container_baseInfo"]/table[1]/tbody/tr[2]/td/div[2]/text/text()')[0]
regist_time_content = self.replace_Str(regist_time_content)
print(regist_time_content)
验证
网站截图如下:
反爬结果如下:
2.动态kg
思路
分析网页发现,那个图d3是动态的,所以猜想在xhr中,于是来到xhr筛选,我们发现了我们先想要的数据!
没错,就是这个json数据!
实现
json获取与存储!
代码语言:javascript复制def get_kgJson(self,url):
raw_html = self.get_html(url).json()
#写json文件
with open('kg.json', "w") as f:
# indent缩进,separators是否去除空格,默认去除!
f.write(json.dumps(raw_html["data"], sort_keys=False, indent=4, separators=(',', ': '), ensure_ascii=False))
哈哈,有数据了,以后可以搞个大的知识图谱可视化!