记录大众点评的字体反爬——Css+svg

 

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

 

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

定位到元素在css里的位置

 

打开url找到文字

 

介绍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 标签和字对应起来,进行全局替换

代码如下:

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)

在爬取到结果后有些字没解析出来,发现有两种text形式

一种带路径的textPath,行数在d=“xx”的M里

另一种是text,行数在text标签里y的值

两种格式不同需要分别处理

 

上面函数返回一个元组包含字体坐标y的参考值和字体内容,fw是字体宽度,如下所示

 

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]

根据class的坐标在svg里计算是哪个字,函数传入的ft是单个class元祖

y坐标定位文字所在行数,x坐标是元组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
})

抓一下店名评论数评论评分电话地址等

用的库

 

大众点评不只使用一种反爬,还用了自定义字体,自定义字体已研究过

转载于:https://www.cnblogs.com/shenyiyangle/p/10730872.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
JS+SVG流程图主动连线是一种通过JavaScript和SVG(可缩放矢量图形)来实现的流程图绘制方式。它可以实现在流程图中的不同节点之间绘制连线,以表示它们之间的关系和流转。 下面是JS+SVG流程图主动连线的基本步骤: 1. 创建SVG容器:使用HTML中的`<svg>`标签创建一个SVG容器,设置宽度和高度等属性。 2. 绘制节点:使用SVG的基本形状元素(如`<rect>`、`<circle>`、`<ellipse>`等)或者自定义路径(`<path>`)来绘制流程图中的节点。可以设置节点的位置、大小、样式等属性。 3. 绘制连线:使用SVG的`<line>`或者`<path>`元素来绘制节点之间的连线。可以设置连线的起点、终点、样式等属性。可以通过计算节点的位置来确定连线的起点和终点。 4. 添加事件监听:使用JavaScript为节点和连线添加事件监听器,以实现交互功能。例如,可以为节点添加点击事件,当点击节点时触发相应的操作。 5. 更新连线:当节点位置发生变化时,需要更新相应的连线。可以通过修改连线的起点和终点来实现。 6. 其他功能:根据需求,还可以添加其他功能,如节点拖拽、连线编辑等。 总结起来,JS+SVG流程图主动连线的流程包括创建SVG容器、绘制节点、绘制连线、添加事件监听、更新连线等步骤。通过JavaScript和SVG的组合,可以实现灵活、交互性强的流程图绘制效果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值