参考博客:http://www.cnblogs.com/eastonliu/p/9925652.html
实习僧招聘的网站采用了字体反爬,在页面上显示正常,查看源码关键信息乱码,如下图所示:
查看网页源码也是看不到关键信息:
查了一下是css3支持自定义字体,实习僧技术人员把一些字体换成了自定义的字体,浏览器上可以显示,后台就看不到了。
1.首先找到这些字体是在哪定义的。
右键查看网页源码,查找font-face,就会看到字体信息(加密的数据太多):
可以看到这些字体源是用了base64加密,用base64库进行解密,把解密后的字体文件保存到shixi.ttf中,下载一个字体软件FontCreator。链接:https://pan.baidu.com/s/1BPRhWYvOs6KFrgNQ4h7m_g 提取码:1fa4
1 def parse_ttf(): 2 font_face = " 源码上的font-face" 3 b = base64.b64decode(font_face) 4 with open('shixi.ttf', 'wb') as f: 5 f.write(b)
用软件打开这个字体文件,可以右键-Captions-Codepoints选择排序方式:
可以看到这是网页替换的字体,例如:e588---1,ebbc---5.
2.接下来就是找到这些字体和源码中相应位置字符的对应关系。
ttf文件直接打不开,可以转换成xml文件打开或者用from fontTools.ttLib import TTFont 这个库打开。
1 def font_dict(): 2 font = TTFont('shixi.ttf') 3 font.saveXML('shixi.xml')
打开shixi.xml,找到cmap,这里保存了编码和字体的对应关系。
接下来就是获取这种对应关系,code所示的就是网页上的源码形式,但是用getBestCmap()函数获取后又变成十进制的数了,所以需要用hex()函数将10进制整数转换成16进制,以字符串形式表示成原来的行是。
这里有一个坑,第一行的map没有用,如果不删除接下来没办法解析。
1 def font_dict(): 2 font = TTFont('shixi.ttf') 3 font.saveXML('shixi.xml') 4 ccmap = font['cmap'].getBestCmap() 5 print("ccmap:\n",ccmap) 6 newmap = {} 7 for key,value in ccmap.items(): 8 # value = int(re.search(r'(\d+)', ccmap[key]).group(1)) - 1 9 #转换成十六进制 10 key = hex(key) 11 value = value.replace('uni','') 12 a = 'u'+'0' * (4-len(value))+value 13 newmap[key] = a 14 print("newmap:\n",newmap) 15 #删除第一个没用的元素 16 newmap.pop('0x78') 17 #加上前缀u变成unicode.... 18 for i,j in newmap.items(): 19 newmap[i] = eval("u" + "\'\\" + j + "\'") 20 print("newmap:\n",newmap) 21 22 new_dict = {} 23 #根据网页上显示的字符样式改变键值对的显示 24 for key, value in newmap.items(): 25 key_ = key.replace('0x', '&#x') 26 new_dict[key_] = value 27 28 return new_dict
这样就得到了网页代码和实际字符额对应关系,如下:
'0xe06b': '天', '0xe0ce': '个', '0xe0d2': 'p', '0xe0d4': 'K', '0xe109': 's'
3.替换网页上的编码,提取正确的信息。
下面是全部源码:
1 #coding=utf-8 2 #milo22233060@gmail.com 3 #2018/11/8 17:01 4 import requests 5 import re 6 from lxml import etree 7 import base64 8 import json 9 import pymysql 10 import time 11 from fontTools.ttLib import TTFont 12 def parse_ttf(): 13 font_face = "" 14 b = base64.b64decode(font_face) 15 with open('shixi.ttf', 'wb') as f: 16 f.write(b) 17 #处理字体问题,返回字体对应的字典 18 def font_dict(): 19 font = TTFont('shixi.ttf') 20 font.saveXML('shixi.xml') 21 ccmap = font['cmap'].getBestCmap() 22 print("ccmap:\n",ccmap) 23 newmap = {} 24 for key,value in ccmap.items(): 25 # value = int(re.search(r'(\d+)', ccmap[key]).group(1)) - 1 26 #转换成十六进制 27 key = hex(key) 28 value = value.replace('uni','') 29 a = 'u'+'0' * (4-len(value))+value 30 newmap[key] = a 31 print("newmap:\n",newmap) 32 #删除第一个没用的元素 33 newmap.pop('0x78') 34 #加上前缀u变成unicode.... 35 for i,j in newmap.items(): 36 newmap[i] = eval("u" + "\'\\" + j + "\'") 37 print("newmap:\n",newmap) 38 39 new_dict = {} 40 #根据网页上显示的字符样式改变键值对的显示 41 for key, value in newmap.items(): 42 key_ = key.replace('0x', '&#x') 43 new_dict[key_] = value 44 45 return new_dict 46 47 #开始爬取,替换字体 48 def crawl(url,new_dict): 49 headers = { 50 'User_Agent': "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36", 51 } 52 response = requests.get(url, headers=headers) 53 # print(response.text) 54 html = response.text 55 # print(new_dict) 56 #测试这个font-face是不是对的 57 58 for key,value in new_dict.items(): 59 if key in html: 60 html = html.replace(key,value) 61 # print('yes') 62 else: 63 pass 64 # print('no') 65 # print(html) 66 html = etree.HTML(html) 67 result = html.xpath("//ul[@class='position-list']//li") 68 69 #获取职位名称,地址,公司名称,薪水,链接 70 result_data = [] 71 for element in result: 72 data = {} 73 try: 74 link = 'https://www.shixiseng.com'+element.xpath(".//div[1]//div[1]//a/@href")[0] 75 position_name = element.xpath(".//div[1]//div[1]//a/text()")[0] 76 company_name = element.xpath(".//div[1]//div[2]//a/text()")[0] 77 location = element.xpath(".//div[2]//div[1]/text()")[0] 78 salary = element.xpath(".//div[2]//div[2]//span[1]/text()")[0] 79 week = element.xpath(".//div[2]//div[2]//span[2]/text()")[0] 80 month = element.xpath(".//div[2]//div[2]//span[3]/text()")[0] 81 except: 82 print('wrong!') 83 print(position_name,location,company_name,salary,link,week,month) 84 data['position_name'] = position_name 85 data['company_name'] = company_name 86 data['location'] = location 87 data['salary'] = salary 88 data['week'] = week 89 data['month'] = month 90 data['link'] = link 91 result_data.append(data) 92 print(result_data) 93 return result_data 94 if __name__ == '__main__': 95 url = 'https://www.shixiseng.com/interns?k=Python&p=' 96 parse_ttf() 97 data = font_dict() 98 print(data) 99 result = [] 100 for i in range(2): 101 result.extend(crawl(url+str(i+1),data)) 102 print(result)
font-face会经常变化,这就需要及时更新这个数据。
欢迎指正。