爬虫高级案例(2):大众点评爬虫-CSS加密
作者:互联网
文章目录
一、基本流程
在大众点评上搜索例如酒店
我们通过开发者工具F12查看数据,发现一些数字等数据都被加密无法看到
我们构建代码简单访问一下,发现数字确实被加密,无法显示,因此我们需要破解该数字
import requests
url = "http://www.dianping.com/search/keyword/2/0_%E9%85%92%E5%BA%97"
headers = {
"user-agent": "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36",
}
response = requests.get(url=url, headers=headers)
print(response.content.decode("utf-8"))
二、发现woff文件
回到刚才的字体,我们发现类名为shopNum
点进去看一下该css文件
格式化内容后,我们看到.woff后缀的文件
这是一种字体文件,有两个是重复,因此大概先按三个文件算,我们将这三个文件地址复制到浏览器地址,会自动下载这三个文件
三、查看woff文件
下载好文件后,我们需要下载可以打开该类型文件的工具,要下载一款工具fontcreator
下载地址:https://www.onlinedown.net/soft/88758.htm
下载好后打开刚才的三个文件。文件—打开—刚才下载的文件
打开这个3个woff
文件发现文字内容和顺序是一样的,只是上面的uni符号不同。
四、确定woff文件
回顾一下刚才的文件类名
找到css文件
确定此处为f91efe97.woff
文件的加密.复制响应内容中的字体,然后去woff,ctrl+f寻找,下面我们就来看一下。
前两个复制出来为9,后边一个为4,与一开始看到的994吻合
五、python读取woff
woff文件可以理解为键值对,键是uni+16进制的字符,值就是字体。现在思路就是爬取网页中的信息,然后去对应的wolf文件中去找对应的字体,那现在有个问题,woff文件怎么转键值对,目前没有好的办法,只能自己将字体一个一个复制出来,这里整理之后的:
word_string=' .1234567890店中美家馆小车大市公酒行国品发电金心业商司超生装园场食有新限天面工服海华水房饰城乐汽香部利子老艺花专东肉菜学福饭人百餐茶务通味所山区门药银农龙停尚安广鑫一容动南具源兴鲜记时机烤文康信果阳理锅宝达地儿衣特产西批坊州牛佳化五米修爱北养卖建材三会鸡室红站德王光名丽油院堂烧江社合星货型村自科快便日民营和活童明器烟育宾精屋经居庄石顺林尔县手厅销用好客火雅盛体旅之鞋辣作粉包楼校鱼平彩上吧保永万物教吃设医正造丰健点汤网庆技斯洗料配汇木缘加麻联卫川泰色世方寓风幼羊烫来高厂兰阿贝皮全女拉成云维贸道术运都口博河瑞宏京际路祥青镇厨培力惠连马鸿钢训影甲助窗布富牌头四多妆吉苑沙恒隆春干饼氏里二管诚制售嘉长轩杂副清计黄讯太鸭号街交与叉附近层旁对巷栋环省桥湖段乡厦府铺内侧元购前幢滨处向座下臬凤港开关景泉塘放昌线湾政步宁解白田町溪十八古双胜本单同九迎第台玉锦底后七斜期武岭松角纪朝峰六振珠局岗洲横边济井办汉代临弄团外塔杨铁浦字年岛陵原梅进荣友虹央桂沿事津凯莲丁秀柳集紫旗张谷的是不了很还个也这我就在以可到错没去过感次要比觉看得说常真们但最喜哈么别位能较境非为欢然他挺着价那意种想出员两推做排实分间甜度起满给热完格荐喝等其再几只现朋候样直而买于般豆量选奶打每评少算又因情找些份置适什蛋师气你姐棒试总定啊足级整带虾如态且尝主话强当更板知己无酸让入啦式笑赞片酱差像提队走嫩才刚午接重串回晚微周值费性桌拍跟块调糕'
所有的文字按照顺序复制组合成了一个字符串,怎么确定顺序呢?可以通过python读取woff,找到对应的字体的顺序数字,这样拿这个数字去字符串中通过下标获取就可以了。
- python读取woff,需要安装fonttools
pip install fonttools
- 使用fonttools读取woff
from fontTools.ttLib import TTFont
tagName = TTFont("f91efe97.woff")
print(tagName.getGlyphOrder())
利用tagName.getGlyphOrder()
结果为键和word_string为值,组成对应的字典
# -*- coding:utf-8 -*-
from fontTools.ttLib import TTFont
# 读取文件的编码,和自己的字符串
tagName = TTFont("f91efe97.woff")
tag_name_list = tagName.getGlyphOrder()
word_string = ' .1234567890店中美家馆小车大市公酒行国品发电金心业商司超生装园场食有新限天面工服海华水房饰城乐汽香部利子老艺花专东肉菜学福饭人百餐茶务通味所山区门药银农龙停尚安广鑫一容动南具源兴鲜记时机烤文康信果阳理锅宝达地儿衣特产西批坊州牛佳化五米修爱北养卖建材三会鸡室红站德王光名丽油院堂烧江社合星货型村自科快便日民营和活童明器烟育宾精屋经居庄石顺林尔县手厅销用好客火雅盛体旅之鞋辣作粉包楼校鱼平彩上吧保永万物教吃设医正造丰健点汤网庆技斯洗料配汇木缘加麻联卫川泰色世方寓风幼羊烫来高厂兰阿贝皮全女拉成云维贸道术运都口博河瑞宏京际路祥青镇厨培力惠连马鸿钢训影甲助窗布富牌头四多妆吉苑沙恒隆春干饼氏里二管诚制售嘉长轩杂副清计黄讯太鸭号街交与叉附近层旁对巷栋环省桥湖段乡厦府铺内侧元购前幢滨处向座下臬凤港开关景泉塘放昌线湾政步宁解白田町溪十八古双胜本单同九迎第台玉锦底后七斜期武岭松角纪朝峰六振珠局岗洲横边济井办汉代临弄团外塔杨铁浦字年岛陵原梅进荣友虹央桂沿事津凯莲丁秀柳集紫旗张谷的是不了很还个也这我就在以可到错没去过感次要比觉看得说常真们但最喜哈么别位能较境非为欢然他挺着价那意种想出员两推做排实分间甜度起满给热完格荐喝等其再几只现朋候样直而买于般豆量选奶打每评少算又因情找些份置适什蛋师气你姐棒试总定啊足级整带虾如态且尝主话强当更板知己无酸让入啦式笑赞片酱差像提队走嫩才刚午接重串回晚微周值费性桌拍跟块调糕'
# 一一对应组成字典
tag_name_dict = {}
for index, value in enumerate(word_string):
tag_name_dict[tag_name_list[index]] = value
print(tag_name_dict)
六、分析及其代码
字体破解思路基本已经定好,接下来我们分析页面,查看获取列表页内容会遇到什么样的情况
店名可以直接获取
星级数一般类名中的数字下划线后给出,数字对应的是星级,10个数为一个星
评论数和人均金额,评论数有的加密有的未加密,有的还为-,多个情况需要都考虑
上述情况只加密了一个数字
上述情况的未加密,显示一个-,因此要考虑多个情况
代码如下,只获取部分字段,其他原理相同
# -*- coding:utf-8 -*-
import requests
from fontTools.ttLib import TTFont
from lxml import etree
def get_word_string():
"""获取所有字"""
with open("./word_string.txt", "r", encoding="utf-8") as file:
return file.read().strip('\n')
def get_word_dict(name):
"""读取指定的woff得到字体"""
if name == "tagName" or name == "shopNum":
woff_name = "f91efe97.woff"
elif name == "address":
woff_name = "b0ddd6c0.woff"
elif name == "reviewTag":
woff_name = '9f702fd5.woff'
# 读取文件的编码,和自己的字符串并 一一对应组成字典
word_dict = {}
tag_name_list = TTFont(woff_name).getGlyphOrder()
word_string = get_word_string()
for index, value in enumerate(word_string):
word_dict[tag_name_list[index]] = value
return word_dict
def get_response(url):
# 登录成功后的cookie值,可以进行翻页
headers = {
"user-agent": "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36",
}
response = requests.get(url=url, headers=headers)
return response
if __name__ == '__main__':
# 解析页面
url = 'http://www.dianping.com/search/keyword/2/0_%E9%85%92%E5%BA%97'
content = get_response(url).content.decode("utf-8")
xpath_obj = etree.HTML(content)
# 获取该页的数据,十五条
li_list = xpath_obj.xpath('//div[@id="shop-all-list"]//ul//li')
for li in li_list:
item = dict()
# item["shop_url"] = li.xpath("./div[1]/a/@href")[0] # 店铺的url
# item["shop_img_url"] = li.xpath("./div[1]/a/img/@src")[0] # 店铺图片的url
item["shop_name"] = li.xpath("./div[1]/a/img/@title")[0] # 店铺名称
# 店铺的星级一般通过类名展现出来了,那个数字就代表星数,因此切割出来
star_class = li.xpath('.//*[@class="star_icon"]/span[1]/@class')[0]
item["shop_star"] = star_class.split(" ")[1].split("_")[-1] # 店铺评分
# 评论数
item["shop_comment_num"] = ''
class_name = li.xpath('./div[2]/div[2]/a[1]/b/svgmtsi/@class')
if class_name: # 有加密
class_name = class_name[0]
word_dict = get_word_dict(class_name)
for unicode in li.xpath('./div[2]/div[2]/a[1]/b//text()'):
# 1字体可能不加密
if unicode == '1':
num = '1'
else:
# 0和匹配的不一样,可能更新
unicode = 'uni' + ''.join(list(map(lambda b: hex(b)[2:], ord(unicode).to_bytes(2, 'big'))))
num = word_dict.get(unicode, '0')
item["shop_comment_num"] += num
else: # 没有加密
item["shop_comment_num"] = "".join(li.xpath('./div[2]/div[2]/a[1]/b//text()')) # 评论数
# 人均消费
item["shop_avg_money"] = ''
class_name = li.xpath('./div[2]/div[2]/a[2]/b/svgmtsi/@class')
if class_name: # 有加密
class_name = class_name[0]
word_dict = get_word_dict(class_name)
for unicode in li.xpath('./div[2]/div[2]/a[2]/b//text()'):
# 1字体可能不加密
if unicode == '¥':
num = ''
if unicode == '¥1':
num = '1'
else:
# 0和匹配的不一样,可能更新
unicode = 'uni' + ''.join(list(map(lambda b: hex(b)[2:], ord(unicode).to_bytes(2, 'big'))))
num = word_dict.get(unicode, '')
item["shop_avg_money"] += num
else: # 没有加密
item["shop_avg_money"] = "".join(li.xpath('./div[2]/div[2]/a[2]/b//text()')) # 人均消费
print(item)
标签:word,name,woff,爬虫,li,加密,div,class,CSS 来源: https://blog.csdn.net/qq_40558166/article/details/113868037