1. 程式人生 > 實用技巧 >Python3 爬蟲-字型數字反爬

Python3 爬蟲-字型數字反爬

  • 爬取網站:http://www.dianping.com/xian/ch0
  • 反爬措施:對於某些數字和中文不是直接使用文字顯示,如下圖,對於"189條點評"中的8和9兩個數字,"人均¥283"中的2、8和3三個數字,對於 "灞臨路營背後西北200米"中的五個中文,都是經過一層字型加密
 1 <!--HTML程式碼-->
 2 <b>1<svgmtsi class="ehrz7r"></svgmtsi><svgmtsi class="ehr2kb"></svgmtsi></b>條點評
 3 
 4 人均<b><
svgmtsi class="ehr146"></svgmtsi><svgmtsi class="ehrz7r"></svgmtsi><svgmtsi class="ehr1oj"></svgmtsi></b> 5 6 <span class="addr"> 7 8 <svgmtsi class="kur669"></svgmtsi> 9 <svgmtsi class="kurrwe"></svgmtsi> 10 營背後 11
<svgmtsi class="kur55z"></svgmtsi> 12 <svgmtsi class="kurfvx"></svgmtsi> 13 <svgmtsi class="kurs1w"></svgmtsi> 14 200米 15 </span>
  • 解決方法:F12開啟谷歌瀏覽器的開發者工具,找到Network,檢索其中的css檔案和svg檔案
  • 對於破解中文和破解數字方法是一樣的,上述檔案中css檔案屬於定位檔案,根據在css中獲取的位置資訊查詢svg中對應位置的資料
  • CSS定位檔案解析
1 /*CSS檔案中部分CSS定位資訊*/
2 .ehrz7r{background:-19.0px -100.0px;}
3 .ehr2kb{background:-163.0px -100.0px;}
4 .kur669{background:-300.0px -145.0px;}
5 .kurrwe{background:-348.0px -96.0px;}
1 '獲取定位資訊'
2 def get_coordinate_value(css_url, class_):
3     'css_url為css檔案連結;class_為需要獲取座標值的class值,如ehrz7r;返回值為一個二維座標'
4     # 比如ehrz7r這個class值,獲取對應的座標值為 19,100
5     css_html = requests.get(css_url).text
6     info_css = re.findall(r'%s{background:-(\d+).0px -(\d+).0px' % class_, css_html, re.S)[0]
7     return info_css
  • 包含數字的svg檔案,以及對應HTML原始碼,和根據樣式類解析出數字的python函式
 1 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
 2 <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
 3 <svg xmlns="http://www.w3.org/2000/svg" version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" width="650px" height="180.0px">
 4 <style>text {font-family:Microsoft YaHei,Hiragino Sans GB;font-size:12px;fill:#999;}</style>
 5     <text x="12 24 36 48 60 72 84 96 108 120 132 144 156 168 180 192 204 216 228 240 252 264 276 288 300 312 324 336 348 360 372 384 396 408 420 432 444 456 468 480 492 504 516 528 540 552 564 576 588 600 612 624 636 648 660 672 684 696 708 720 732 744 756 768 780 792 
 6              804 816 828 840 852 864 876 888 900 912 924 936 948 960 972 984 996 1008 1020 1032 1044 1056 1068 1080 1092 1104 1116 1128 1140 1152 1164 1176 1188 1200 1212 1224 1236 1248 1260 1272 1284 1296 1308 1320 1332 1344 1356 1368 1380 1392 1404 1416 1428 1440 " 
 7           y="49">22463826571078658658528825346040036308750917596095</text>
 8     <text x="12 24 36 48 60 72 84 96 108 120 132 144 156 168 180 192 204 216 228 240 252 264 276 288 300 312 324 336 348 360 372 384 396 408 420 432 444 456 468 480 492 504 516 528 540 552 564 576 588 600 612 624 636 648 660 672 684 696 708 720 732 744 756 768 780 792 
 9              804 816 828 840 852 864 876 888 900 912 924 936 948 960 972 984 996 1008 1020 1032 1044 1056 1068 1080 1092 1104 1116 1128 1140 1152 1164 1176 1188 1200 1212 1224 1236 1248 1260 1272 1284 1296 1308 1320 1332 1344 1356 1368 1380 1392 1404 1416 1428 1440 " 
10           y="85">52284412679211790342481439513122587316130759384393</text>
11     <text x="12 24 36 48 60 72 84 96 108 120 132 144 156 168 180 192 204 216 228 240 252 264 276 288 300 312 324 336 348 360 372 384 396 408 420 432 444 456 468 480 492 504 516 528 540 552 564 576 588 600 612 624 636 648 660 672 684 696 708 720 732 744 756 768 780 792 
12              804 816 828 840 852 864 876 888 900 912 924 936 948 960 972 984 996 1008 1020 1032 1044 1056 1068 1080 1092 1104 1116 1128 1140 1152 1164 1176 1188 1200 1212 1224 1236 1248 1260 1272 1284 1296 1308 1320 1332 1344 1356 1368 1380 1392 1404 1416 1428 1440 " 
13           y="124">98461097490779670416</text>
14 </svg>
 1 def get_completed_nums(svg_num_url, css_url, class_list):
 2     'svg_num_url為包含數字的svg檔案連結;css_url為css檔案連結;class_list為需要進行處理獲取對應數字的的class值集合'
 3     completed_nums = ''
 4     result_svg = requests.get(svg_num_url).text
 5     
 6     # svg頁面原始碼中text標籤內的文字值 
 7     # a:22463826571078658658528825346040036308750917596095
 8     # b:52284412679211790342481439513122587316130759384393
 9     # c:98461097490779670416
10     a, b, c = re.findall('y=.*?>(.*?)<', result_svg, re.S)
11     
12     # text標籤內的y屬性值 
13     # 示例: 49, 85, 124
14     y1, y2, y3 = re.findall('y="(.*?)">', result_svg, re.S)
15     
16     # 字型大小 # 示例:x = 12,......
17     divisor = eval(re.search('x="(\d{2}) ', result_svg, re.S).group(1))
18     
19     for class_ in class_list:
20         # 比如ehrz7r這個class值,獲取對應的座標值為 19,100,則是c[19//12]=c[1]=8
21         # 比如ehr2kb這個class值,獲取對應的座標值為 163,100,則是c[163//12]=c[13]=9
22         x, y = get_coordinate_value(css_url, class_) # 獲取某一個class值的座標值
23         x, y = int(x), int(y)
24         if y < int(y1):
25             completed_nums += a[x // divisor]
26         elif y < int(y2):
27             completed_nums += b[x // divisor]
28         elif y < int(y3):
29             completed_nums += c[x // divisor]
30     return completed_nums
  • 包含中文的svg檔案,以及對應HTML原始碼,和根據樣式類解析出中文的python函式
 1 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
 2 <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
 3 <svg xmlns="http://www.w3.org/2000/svg" version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" width="650px" height="280.0px">
 4 <style>text {font-family:Microsoft YaHei,Hiragino Sans GB;font-size:12px;fill:#999999;}</style>
 5     <text x="0" y="41">遼香金莞關華夏振賓頭北和桂創肇徐健家迎濰康黑汕晉教二七遠樂疆永昌漢博慶層光鄭贛林民佛沿綿溫府南鹽鄉陽</text>
 6     <text x="0" y="74">泰蘇皇紹寧龍凰義京花通茂石衡縣銀威開韶九衢一黃州軍才平誼站重川東嶽島港濟充肅保長河愛弄生鳳常臺連園津</text>
 7     <text x="0" y="120">場昆洛江體農名鞍學武惠合齊市泉淄沈蒙幸嘉進古業大中機莊解三路年隆主上建曙育福放灣濱圳興四團富公肥浙天</text>
 8     <text x="0" y="169">諧六木號山無村風省門樓前文紅明鎮廈交源深杭吉揚八湛臨擁遵工安治設春區沙廊雲環坊淮岡魯人青爾西城宜孝珠</text>
 9     <text x="0" y="212">太澳錦新心湖結五勝梅內朝襄信藏陝邢哈街成遷旗煙德感海波化廣十清向錫定秦宿友徽汾烏封貴甘道祥都利</text>
10 </svg>
 1 def get_completed_font_425(svg_font_url, css_url, class_list):
 2     """
 3     svg_font_url:字型的svg檔案連結;css_url為css檔案連結;class_list為需要進行處理獲取對應數字的的class值集合
 4     處理文字 測試期間規律:svg原始碼中通過y確定偏移字型所在文字行, 然後通過text[x//divisor]獲取正常字元
 5     """
 6     completed_font = ''
 7     svg_font_text = re.sub('<\?xml.*?\?>', '', requests.get(svg_font_url).text)
 8     
 9     # 獲取y、text值組成的元組列表
10     y_text_list = re.findall('y="(.*?)">(.*?)<', svg_font_text, re.S)
11     
12     # 獲取字型大小12
13     divisor = eval(re.search('font-size:(\d+)px', svg_font_text, re.S).group(1)) 
14     
15     for class_ in class_list:
16         # class對應座標值 比如kur669的座標為300,145;kurrwe的座標為348,96
17         x, y = get_coordinate_value(css_url, class_)
18         x, y = int(x), int(y)
19         # 獲取當前class對應y_text_list中文字所在文字行
20         class_text = [tup[-1] for tup in y_text_list if y < int(tup[0])][0]
21         # 根據偏移量獲取最終需要的文字 300//12=25
22         target_text = class_text[x // divisor]
23         completed_font += target_text
24     return completed_font