地址:http://www.dianping.com/shop/9964442
好多字沒了,替代的是<x class="xxx"></x>這種css標簽
定位到位置
找到文字
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>
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.用字替換標簽
代碼:
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結果
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)
結果里有些字沒解析出來,發現有兩種文字形式
一種帶路徑的textPath,行數y在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找到所有坐標
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找到具體文字
y是文字所在行數,x字體寬度
replace_dic=[] for i in css_list: replace_dic.append({"code":i[0],"word":font_parser(i)})
根據坐標,找到映射關系
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 })
替換后店名評論數評論評分電話地址等結果
用的庫