字体反爬–css+svg反爬

释放双眼,带上耳机,听听看~!

这个验证码很恶心,手速非常快才能通过。。

字体反爬--css+svg反爬

地址:http://www.dianping.com/shop/9964442

 字体反爬--css+svg反爬

检查一下看到好多字没有了,替代的是<x class=\”xxx\”></x>这种标签

字体反爬--css+svg反爬

ctrl+右键点style里第一行,定位到元素在css里的位置

 字体反爬--css+svg反爬

打开url找到了文字

字体反爬--css+svg反爬

 

下面讲SVG

字体反爬--css+svg反爬

 svg可缩放矢量图形基于可扩展标记语言,是用代码画矢量图的,如图 

svg也可以写入文本如下图,xy是相对于svg标签的坐标,默认单位px

字体反爬--css+svg反爬

 

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是字体宽度,后面计算坐标会用到

字体反爬--css+svg反爬

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和坐标

字体反爬--css+svg反爬

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和字的关系存在字典里

字体反爬--css+svg反爬

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在页面里应该是空格,可以替换掉,结果如下

字体反爬--css+svg反爬

用过的库

字体反爬--css+svg反爬

以上是全部代码

写完以后看到大众点评在此基础上添加了反爬方式,把自定义字体反爬和本篇讲的字体反爬结合起来

字体反爬--css+svg反爬

字体反爬--css+svg反爬

自定义字体反爬可以参考我写的前两篇

 

给TA打赏
共{{data.count}}人
人已打赏
随笔日记

Spring Boot入门(三):使用Scheduled注解实现定时任务

2020-11-9 4:28:04

随笔日记

vue-router导航守卫(router.beforeEach())的使用

2020-11-9 4:28:06

0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧
个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索