这次爬取的目标是大众点评里餐厅的信息以及用户的评论。
大众点评的反爬内容比较丰富,这里也只是记录了如何通过selenium模拟访问大众点评,以及大众点评的woff文件构建字典并对加密文字进行替换。
目标url='http://www.dianping.com/shop/G7RgscHLjDjXY9hg'
进入目标网页,对我们想要的商店名进行分析,发现它在开发者工具与页面显示的并不一样,
同时发现这个字体的"font-family"属性为’PingFangSC-Regular-address’。
继续分析其他加密字体,可以发现这样一个规律:
不同位置有不同font-family:(店)中文:PingFangSC-Regular-address
(店)数字:PingFangSC-Regular-num
(顾客)评价:PingFangSC-Regular-review
(店)营业时间 数字:PingFangSC-Regular-hours
(店)营业时间 中文:PingFangSC-Regular-shopdesc
推荐菜:PingFangSC-Regular-dishname
同时可以注意到:加密的字中都有一个相同的css地址,如上图箭头所指。
http://s3plus.meituan.net/v1/mss_0a06a471f9514fc79c981b5466f56b91/svgtextcss/73c76f0d91f3b846605b9aa7a7cfc6e8.css
转到链接所指向的网页地址,可以发现该文件是以这样的形式构成的:
这样的结构正好有6个,与上文分析的数目相同。
@font-face {
font-family:"PingFangSC-Regular-xxxxxx";src:url("//s3plus.meituan.net/v1/mss_73a511b8f91f43d0bdae92584ea6330b/font/xxxx.eot");src:url("//s3plus.meituan.net/v1/mss_73a511b8f91f43d0bdae92584ea6330b/font/xxxxx.eot?#iefix")format("embedded-opentype"),url("//s3plus.meituan.net/v1/mss_73a511b8f91f43d0bdae92584ea6330b/font/xxxxx.woff");}.dishname {
font-family:'PingFangSC-Regular-xxxxx';}
其中的.woff文件就是我们要用来解密的字体文件,下载字体文件并通过
http://blog.luckly-mjw.cn/tool-show/iconfont-preview/index.html
网址在线预览一下:(这里以adders为例,每天的字体文件可能不同,仅做示范)
可以到网页中加密的文字的Unicode编码能与woff文件中的“吉”对应,因此只要利用woff文生成一个字典,就能通过字典替换得到真正的文字了。
因此 编写爬虫的基本思路为:
1.获取网页内容
2.获得带有woff文件地址的css文件
3.对css文件发起请求得到woff文件的地址
4.分别对woff文件的地址发起请求,得到所有的woff文件
5.利用woff文件生成字典
6.利用字典解密,并保存得到的数据
引用的库
import requests
from lxml import etree
from selenium import webdriver
import time
import numpy
import re
from fontTools.ttLib import TTFont # 解析字体文件的包from PIL import Image, ImageDraw, ImageFont #绘制图片from selenium.webdriver.chrome.options import Options
from aip import AipOcr
import os
获取网页内容
url='http://www.dianping.com/shop/G7RgscHLjDjXY9hg'
options = Options()
options.add_experimental_option("debuggerAddress","127.0.0.1:9222")
wb=webdriver.Chrome(options=options)
wb.get(url)
re_text=wb.page_source
#数据读取并保存
dz=DZDP_HTML(re_text=re_text)
dc=dz.dict_dict#传入总字典
tree=etree.HTML(re_text)
data=get_datas_by_xpath(tree,dc)
json_str = json.dumps(data,indent=4,ensure_ascii=False)withopen('cs.json','w',encoding='utf-8')as f:
f.write(json_str)
由于直接使用selenium访问会被检测到,参考了https://www.cnblogs.com/triangle959/p/12015179.html
文章采用以上方式避免了被检测成功获取网页源代码
获取css地址,匹配woff地址
defget_fonts_css(re_text):# 传入selenium得到的网页内容 通过正则提取到各个字体对应的url链接
css_gz=re.compile(r'(s3plus.meituan.net.*?.\.css)',re.S)
css_url="http://"+css_gz.search(re_text).group(1)
req=requests.get(url=css_url).text
# return req.text
url_gz=re.compile(r',url\("\/\/(s3plus.meituan.net.*?\.woff)',re.S)
font_gz=re.compile('font-family: "PingFangSC-Regular-(.*?)";',re.S)
url_list=re.findall(url_gz,req)
font_list=re.findall(font_gz,req)
font_url_dict={}for x,y inzip(url_list,font_list):
font_url_dict[y]=x
return font_url_dict#得到类型名:网址 的字典 件
分别请求,得到各个woff文件
defdown_fonts_url(font_url_dict):# 传入get_fonts_css得到的 字典 遍历后进行下载对应的woff文件for key,url in font_url_dict.items():
url="http://"+url
res=requests.get(url).content
withopen(key+".woff",'wb')as f:print(key+".woff文件下载完成!")
f.write(res)
利用woff文件生成字典
classDZDP_HTML(object):def__init__(self,re_text):super().__init__()dict=self.__get_fonts_css(re_text)
self.__down_fonts_url(dict)
self.num_dict= self.__get_fonts_dict("num")
self.dishname_dict= self.__get_fonts_dict("dishname")
self.review_dict= self.__get_fonts_dict("review")
self.hours_dict= self.__get_fonts_dict("hours")
self.address_dict= self.__get_fonts_dict("address")
self.shopdesc_dict= self.__get_fonts_dict("shopdesc")
self.dict_dict={"num":self.num_dict,"dishname":self.dishname_dict,"review":self.review_dict,"hours":self.hours_dict,"address":self.address_dict,"shopdesc":self.shopdesc_dict
}def__get_fonts_ocr(self,filename):
APP_ID =' '
API_KEY =' '
SECRET_KEY =' '
aipOcr=AipOcr(APP_ID, API_KEY, SECRET_KEY)# 读取图片
filePath = filename+".jpg"defget_file_content(filePath):withopen(filePath,'rb')as fp:return fp.read()# 定义参数变量
optionss ={'detect_direction':'true','language_type':'CHN_ENG',}# 网络图片文字文字识别接口
result = aipOcr.webImage(get_file_content(filePath),optionss)return result
def__get_fonts_dict(self,fontpath):
font = TTFont(fontpath+'.woff')# 打开文件
codeList = font.getGlyphOrder()[2:]
im = Image.new("RGB",(1800,1000),(255,255,255))
dr = ImageDraw.Draw(im)
font = ImageFont.truetype(fontpath+'.woff',40)
count =15
arrayList = numpy.array_split(codeList,count)#将列表切分成15份,以便于在图片上分行显示for t inrange(count):
newList =[i.replace("uni","\\u")for i in arrayList[t]]
text ="".join(newList)
text = text.encode('utf-8').decode('unicode_escape')
dr.text((0,50* t), text, font=font, fill="#000000")
im.save(fontpath+".jpg")
dc={}#输出字典
result=self.__get_fonts_ocr(fontpath)
words_list=result['words_result']for array,word inzip(arrayList,words_list):for arra,wor inzip(array,word["words"]):# arra=str(arra)
arra=arra.replace("uni",r"\u")
dc[arra]=wor
return dc
字典的生成借用了
https://blog.csdn.net/weixin_44606217/article/details/103766197
文章的代码,利用百度识图的api进行文字识别,因此要输入自己的id和key
利用xpath提取信息,并利用字典进行解密.
class_name_list=["shopdesc","address","hours","review","shopdesc","num"]defget_true_words(lists,dc):
add=""for n in lists:
class_num=0
class_name=n.xpath('.//@class')
c=0#去除不属于class_name_list 就可以实现跟加密文字的一一对应确定用哪个字典解密while c<len( class_name):if class_name[c]notin class_name_list:
class_name.remove( class_name[c])else:
c+=1
words=n.xpath('.//text()')for word in words:
w =re.findall(u"[\ue000-\uf999]",word)#正则匹配到的说明是加密字 if w!=Noneandlen(w)!=0:
wo=word.encode('unicode_escape')
wo=str(wo)[3:-1]if wo==Noneor wo=='':continuetry:
c=class_name[class_num]
wo=dc[class_name[class_num]][wo]
add+=wo
except BaseException:print(BaseException)finally:
class_num+=1else:
add+=word
print(u'\xa0'in add)
add=add.replace(u'\xa0',u' ')return add
defget_datas_by_xpath(tree,dc):
data={}#商家信息
shop_name=tree.xpath('//h1[@class="shop-name"]')
add=get_true_words(shop_name,dc)
data["shop_name"]=add
shop_address=tree.xpath('//div[@id="J_map-show"]/span[@class="item"]')
add=get_true_words(shop_address,dc)
data["shop_address"]=add
shop_iphone=tree.xpath('//p[@class="expand-info tel"]')
add=get_true_words(shop_iphone,dc)
data["shop_iphone"]=add
#用户信息
li_list=tree.xpath('//ul[@class="comment-list J-list"]/li')
i=0for li in li_list:
data_user={}
user_name=li.xpath('.//p[@class="user-info"]/a/text()')
user_time=li.xpath('.//span[@class="time"]/text()')
user_contont=li.xpath('.//p[@class="desc"]')
add=get_true_words( user_contont,dc)
data_user["user_name"]=user_name[0]
data_user["user_time"]=user_time[0]
data_user["user_contont"]=add
data["user%s"%i]=data_user
i+=1return data
输出:
版权归原作者 四叶草茶艺师 所有, 如有侵权,请联系我们删除。