字体反爬--css+svg反爬
这个验证码很恶心,手速非常快才能通过。。
地址:http://www.dianping.com/shop/9964442
检查一下看到好多字没有了,替代的是<x class="xxx"></x>这种标签
ctrl+右键点style里第一行,定位到元素在css里的位置
打开url找到了文字
下面讲SVG
svg可缩放矢量图形基于可扩展标记语言,是用代码画矢量图的,如图
svg也可以写入文本如下图,xy是相对于svg标签的坐标,默认单位px
textPath
该元素利用它的xlink:href
属性取得一个任意路径,把字符对齐到路径,于是字体会环绕路径、顺着路径走:
<path id="my_path" d="M 20,20 C 40,40 80,40 100,20" fill="transparent" /> <text> <textPath xlink:href="#my_path">This text follows a curve.</textPath> </text>
就是说textpath根据xlink:href 取得path路径,d里面是路径的路线
关于d内的参数:
M = moveto
L = lineto
H = horizontal lineto
V = vertical lineto
C = curveto
S = smooth curveto
Q = quadratic Bézier curve
T = smooth quadratic Bézier curveto
A = elliptical Arc
Z = closepath
后面用到的只有M和H,M是xy坐标,H是水平线,表示文字方向是水平方向。
参考的资料:https://cloud.tencent.com/developer/section/1423872
所以找字体的思路是
1.找到替换文字的css
2.找到svg
3.拿到css里每个字的坐标,再在svg里计算出具体的字
4.把class和字对应起来,全局替换<x class="xxx"></x>成字
下面是代码:
headers={"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36"} r=requests.get("http://www.dianping.com/shop/9964442",headers=headers) css_url="http:"+re.findall('href="(//s3plus.meituan.net.*?svgtextcss.*?.css)',r.text)[0] css_cont=requests.get(css_url,headers=headers)
拿到css页
svg_url=re.findall('class\^="(\w+)".*?(//s3plus.*?\.svg)',css_cont.text) s_parser=[] for c,u in svg_url: f,w=svg_parser("http:"+u) s_parser.append({"code":c,"font":f,"fw":w})
拿到svg地址解析svg返回解析结果和定位svg的代码,这里用元组,方便排序
def svg_parser(url): r=requests.get(url,headers=headers) font=re.findall('" y="(\d+)">(\w+)</text>',r.text,re.M) if not font: font=[] z=re.findall('" textLength.*?(\w+)</textPath>',r.text,re.M) y=re.findall('id="\d+" d="\w+\s(\d+)\s\w+"',r.text,re.M) for a,b in zip(y,z): font.append((a,b)) width=re.findall("font-size:(\d+)px",r.text)[0] new_font=[] for i in font: new_font.append((int(i[0]),i[1])) return new_font,int(width)
这里要注意svg有两种形式
一种是带textPath有文字路径,文字所在行数得用d=“xx”里的M获得
另一种是text,文字所在行数是text标签里y的值,所以要分开处理。
函数返回两个值一个是字体坐标y的参考值和字体内容的元祖,另一个fw是字体宽度,后面计算坐标会用到
svg解析结果
css_list = re.findall('(\w+){background:.*?(\d+).*?px.*?(\d+).*?px;', '\n'.join(css_cont.text.split('}'))) css_list = [(i[0],int(i[1]),int(i[2])) for i in css_list]
从css里拿到所以class和坐标
def font_parser(ft): for i in s_parser: if i["code"] in ft[0]: font=sorted(i["font"]) if ft[2] < int(font[0][0]): x=int(ft[1]/i["fw"]) return font[0][1][x] for j in range(len(font)): if (j+1) in range(len(font)): if(ft[2]>=int(font[j][0]) and ft[2]< int(font[j+1][0])): x=int(ft[1]/i["fw"]) return font[j+1][1][x]
解析坐标值,获得具体文字,传入的是clss,xy坐标的元祖,根据svg解析结果定位到文字所在的svg,
根据y坐标定位文字所在行数,文字横坐标是元祖的x值/字体宽度,返回具体文字
replace_dic=[] for i in css_list: replace_dic.append({"code":i[0],"word":font_parser(i)})
解析css里的所有class,把class和字的关系存在字典里
rep=r.text for i in range(len(replace_dic)): if replace_dic[i]["code"] in rep: a=re.findall(f'<\w+\sclass="{replace_dic[i]["code"]}"><\/\w+>',rep)[0] rep=rep.replace(a,replace_dic[i]["word"])
根据字典对页面<x class="xxx"></x>标签全局替换
shop=[] shop_name=tree.xpath('//h1[@class="shop-name"]//text()')[0] reviewCount=tree.xpath('//span[@id="reviewCount"]//text()')[0] avgPriceTitle=tree.xpath('//span[@id="avgPriceTitle"]//text()')[0] comment_score=tree.xpath('//span[@id="comment_score"]//text()') comment_score=[i for i in comment_score if i!=" "] addr=tree.xpath('//span[@itemprop="street-address"]/text()')[0] phone=tree.xpath('//p[@class="expand-info tel"]//text()') phone=phone[1]+phone[2] review=[] for li in lis: name=li.xpath('.//a[@class="name"]/text()')[0] comment=li.xpath('.//p[@class="desc"]/text()')[0] review.append({"name":name,"comment":comment}) shop.append({ "shop_name":shop_name, "reviewCount":reviewCount, "avgPriceTitle":avgPriceTitle,"addr":addr, "phone":phone, "review":review })
抓一下店名评论数评论评分电话地址等数据,\xa0在页面里应该是空格,可以替换掉,结果如下
用过的库
以上是全部代码
写完以后看到大众点评在此基础上添加了反爬方式,把自定义字体反爬和本篇讲的字体反爬结合起来
自定义字体反爬可以参考我写的前两篇
- 关于web中的字体, .woff, .eot, .svg
- 将svg文件化成字体图标的步骤
- 黄聪:解决Web部署 svg/woff/woff2字体 404错误
- 解决Web部署 svg/woff/woff2字体 404错误
- Web 字体简介: TTF, OTF, WOFF, EOT & SVG
- SVG字体图标格式解析
- 精简ttf,svg字体库文件,删除多余字体,保留用到字体
- 解决phpWeb部署 svg/woff/woff2字体 Failed to decode downloaded font
- 解决Web部署 svg/woff/woff2字体 404错误
- 解决Web部署 svg/woff/woff2字体 404错误
- 如何制作图标字体(如何将svg转换为css可用的图标字体)
- 解决IIS Web部署 svg/woff/woff2字体找不到问题
- svgtofont.js 自动生成图标字体和彩色图标文件
- 解决Web部署 svg/woff/woff2字体 404错误(转)
- CSS+HTML实例集合一,改变字体(样式,大小),overflow布局属性(如显示隐藏文字等),列表的展开闭合
- 解决Web部署 svg/woff/woff2字体 404错误
- 如何把SVG小图片转换为 html字体图表
- SVG转换成字体,把图标做字体在HTML中使用
- 【转帖】SVG与中文字体_瑞恩科技 ——瑞出东方,恩泽天地
- 在SVG中使用Bootstrap或FontAwesome图标字体