为了找到物美价廉的房子,连夜爬了某租房网站1W多条租房信息

本文的文字及图片来源于网络,仅供学习、交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理
以下文章来源于python数据分析之禅, 作者:小dull鸟
为了找到物美价廉的房子,连夜爬了某租房网站1W多条租房信息文章插图
前言最近要租房子了 , 为了找到物美价廉的房子 , 我昨天连夜爬了某租房网站7000多条租房信息 , 爬取结果如下:
为了找到物美价廉的房子,连夜爬了某租房网站1W多条租房信息文章插图
本次爬取难点在于数字解密 , 好在最后都解决了 , 下面把爬取过程分享给大家
一、分析网页 , 获取原始数据网址为:
为了找到物美价廉的房子,连夜爬了某租房网站1W多条租房信息文章插图
此网页有2类数据:
为了找到物美价廉的房子,连夜爬了某租房网站1W多条租房信息文章插图
第一种是嵌在网页内的数据第二种是axja获取的json数据 , 解析后插入网页对于第一种 , 由于数据在网页中 , 我们只需模拟请求网页 , 解析网页数据 , 把我们需要的数据保存即可:
为了找到物美价廉的房子,连夜爬了某租房网站1W多条租房信息文章插图
由上图可以发现 , 原始网页中 , 户型、价格等数字信息显示不对 , 已被加密 。 这里先不管 , 后面再讲解密 , 爬虫代码如下:
import requestsfrom bs4 import BeautifulSoups = requests.Session()s.headers = {'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8','accept-language': 'en-US,zh;q=0.8,zh-CN;q=0.7,zh-TW;q=0.5,zh-HK;q=0.3,en;q=0.2','referer': '','upgrade-insecure-requests': '1','user-agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:78.0) Gecko/20100101 Firefox/78.0',}s.get(url='')response=s.get('pn1/?PGTID=0d300008-0000-1e0f-27d7-0238e53f2f24 --tt-darkmode-color: #9B9B9B;">对于第二种 , 需要抓包获取数据接口:
为了找到物美价廉的房子,连夜爬了某租房网站1W多条租房信息文章插图
为了找到物美价廉的房子,连夜爬了某租房网站1W多条租房信息文章插图
通过抓包 , 很容易获取数据接口 , 该接口通过pageNum参数控制页码 , 总共有54页 , 返回的是json格式数据 , 代码如下:
import requests,jsonfor page in range(54):url=';basequery=room:j|cityId:1|areaId:1|cateId:8 --tt-darkmode-color: #9B9B9B;">可以发现 , 这部分数据没有加密
二、对第一部分数据进行解码网上有一种方法是找出加密后的文字与数字的对应关系 , 然后进行解密 , 这种方法是不对的 , 因为网页每刷新1次 , 这种对应关系就会重新改变 。
这类问题属于字体加密 , 字体加密一般是网页修改了默认的字符编码集 , 在网页上加载的他们自己定义的字体文件作为字体的样式 , 可以正确地显示数字 , 但是在源码上同样的二进制数由于未加载自定义的字体文件就由计算机默认编码成了乱码 。
为了找到物美价廉的房子,连夜爬了某租房网站1W多条租房信息文章插图
一般来说 , 通用的解决办法是找到字体文件 , 分析文件中的映射关系 。 一般来说 , 字体文件都是作为样式加在加密字体的部位 。
通过测试 , 当取消font-family前面的勾选后 , 网页中的数据开始加密
为了找到物美价廉的房子,连夜爬了某租房网站1W多条租房信息文章插图
所以可以确定 , fangchan-secret最可能是字体加密文件
在源码中Ctrl+F搜索fangchan-secret 寻找字体加密文件
为了找到物美价廉的房子,连夜爬了某租房网站1W多条租房信息文章插图
字体文件是通过base64加密之后放在js里面
下面开始写代码进行解密:
1.用正则将加密部分提取出来 , 然后用base64解码 , 转化成为二进制形式bs64Str = re.findall("charset=utf-8;base64,(.*?)\'\)", response.text)[0]binData = http://kandian.youth.cn/index/base64.decodebytes(bs64Str.encode())2.写入otf字体文件filePath01 = r'\jiemi.otf'with open(filePath01, 'wb') as f:f.write(binData)f.close()3.解析字体库font01 = TTFont(filePath01)utfList = font01['cmap'].tables[0].ttFont.tables['cmap'].tables[0].cmap# c = font.getBestCmap()retList = []for i in getText:if ord(i) in utfList:text = int(utfList[ord(i)][-2:]) - 1else:text = i4.构造解密函数 , 传入加密后的文字 , 返回解析后的数字def convert(getText):bs64Str = re.findall("charset=utf-8;base64,(.*?)\'\)", response.text)[0]binData = http://kandian.youth.cn/index/base64.decodebytes(bs64Str.encode())# 写入otf字体文件filePath01 = r'\jiemi.otf'with open(filePath01, 'wb') as f:f.write(binData)f.close()# 解析字体库font01 = TTFont(filePath01)utfList = font01['cmap'].tables[0].ttFont.tables['cmap'].tables[0].cmap# c = font.getBestCmap()retList = []for i in getText:# ord()以字符作为参数 , 返回对应的Unicode数值if ord(i) in utfList:text = int(utfList[ord(i)][-2:]) - 1else:text = iretList.append(text)return(''.join([str(j) for j in retList]).split('\n'))