python爬取实习僧招聘信息字体反爬

时间:2022-09-18 16:24:34

参考博客:http://www.cnblogs.com/eastonliu/p/9925652.html

实习僧招聘的网站采用了字体反爬,在页面上显示正常,查看源码关键信息乱码,如下图所示:

python爬取实习僧招聘信息字体反爬

查看网页源码也是看不到关键信息:

python爬取实习僧招聘信息字体反爬

查了一下是css3支持自定义字体,实习僧技术人员把一些字体换成了自定义的字体,浏览器上可以显示,后台就看不到了。

1.首先找到这些字体是在哪定义的。

右键查看网页源码,查找font-face,就会看到字体信息(加密的数据太多):

python爬取实习僧招聘信息字体反爬

可以看到这些字体源是用了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选择排序方式:

python爬取实习僧招聘信息字体反爬

python爬取实习僧招聘信息字体反爬

可以看到这是网页替换的字体,例如: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,这里保存了编码和字体的对应关系。

python爬取实习僧招聘信息字体反爬

接下来就是获取这种对应关系,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会经常变化,这就需要及时更新这个数据。

 欢迎指正。