Pythonクローラーフォントの復号化| Dianpingストアの情報収集を示す例としてスキーを取り上げます

  • 1.簡単な説明

  • 2.フォントのクライミング防止処理

    • 2.1。フォントファイルのリンクを取得する

    • 2.2.3種類のフォントと実際の文字の間にマッピング関係を作成します

  • 3.単一ページのショップ情報の分析

  • 4.すべてのページのデータ収集

    • 4.1。データページの数を取得します

    • 4.2。すべてのデータを収集する

  • 5.まとめ

  • 多くの人がPythonを学び、どこから始めればよいのかわかりません。
    多くの人がPythonを学び、基本的な文法を習得した後、どこから始めればよいかわかりません。
    事例研究を行った多くの人々は、より高度な知識を学ぶ方法を知りません。
    これらの3つのタイプの人々のために、私はあなたに優れた学習プラットフォームを提供し、ビデオチュートリアル、電子書籍、およびコースのソースコードを無料で受け取ることができます!??
    ¤QQグループ:232030553

冬はスキーに適した季節ですが、スキーには注意が必要です。たとえば、初心者は上級者向けのトレイルに行かないでください。スキーができるかどうかは少しビープ音が鳴る必要があります。

それでは、今日は、スキーをキーワードとして使用して、Pythonクローラーを使用してDianpingのストア情報を収集する方法を示しましょう。

request.get() による検索結果ページフォームで ページデータを取得し、次にWebページデータ関連ショップを解析して、必要な情報を取得できます。

ただし、クロール処理中に、私たちは、人の消費につき、こうした店舗レビューの数としてその情報を見つけるだろう、と店のアドレスは次のように表示されている Webページ、上 と同様です&#xf622 GETデータインチ Iドンそれが何であるかわからない。これは実際には一種のフォントアンチクライミングであり、すべてを壊します。

収集する必要のあるデータフィールドは次のとおりです。

フィールド 説明 入手方法 フォント
shop_id ストアID 直接入手
shop_name ショップ名 直接入手
shop_star 星の評価を保存する 直接入手
shop_address ショップの住所 直接入手
shop_review 店舗評価数 フォントクロール shopNum
shop_price 店舗の一人当たりの消費量 フォントクロール shopNum
shop_tag_site ショップエリア フォントクロール タグ名
shop_tag_type ショップ分類 フォントクロール タグ名

2.フォントのクライミング防止処理

Dianpingを開き、スキー検索します。検索結果ページでF12キーを押して、開発者モードに入ります。レビュー数を選択すると、クラスがshopNumで、コンテンツが□であることがわかります 。右側のスタイルでは、フォントファミリーがPingFangSC-Regular-shopNumであることがわかります。実際、右側の.cssリンクをクリックすると、フォントファイルのリンクを見つけることができます。フォントのアンチクライミングに関連する他のフィールドに対応するフォントファイルのリンクが異なる可能性があることを考慮して、1回限りの取得のための別の方法を収集します(詳細については次の段落を参照してください)。

アンチクライミングフォント(評価数)

2.1。フォントファイルのリンクを取得する

私たちはウェブページの セクションに向かいます、あなたは写真テキストcssを見つけることができます 、cssそれらの対応するアドレスはフォローアップが含まれています すべてのフォント名を返すようにアドレスを変更するためにrequess.get()リクエストで直接すべてのフォントファイルリンクが使用されますフォントファイルのダウンロードリンク。

フォントクライミング防止(フォントリンク)

-Webページデータを取得するための関数メソッドget_html()を定義します

# 获取网页数据
def get_html(url, headers):   
    try:
        rep = requests.get(url ,headers=headers)
    except Exception as e :
        print(e)
    text = rep.text
    html = re.sub('\s', '', text) #去掉非字符数据
    
    return html

-Webページデータを取得する

import re
import requests
# Cookie部分,直接复制浏览器里的即可
headers = {
        "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.89 Safari/537.36",
        "Cookie":"你的浏览器Cookie",
        }
# 搜索关键字
key = '滑雪'
# 基础url
url = f'https://www.dianping.com/search/keyword/2/0_{key}'
# 获取网页数据
html = get_html(url, headers)

-フォントファイルのリンクを取得

# 正则表达式获取head里图文混排css中的字体文件链接
text_css = re.findall('<!--图文混排css--><linkrel="stylesheet"type="text\/css"href="(.*?)">', html)[0]  
# 'http://s3plus.meituan.net/v1/mss_0a06a471f9514fc79c981b5466f56b91/svgtextcss/29de4c2bc5d95d1e147c3c25a5f4aad8.css'
# 组合成css链接
css_url = 'http:' + text_css
# 获取字体文件链接的网页数据
font_html = get_html(css_url, headers)
# 正则表达式获取 字体信息列表
font_list = re.findall(r'@font-face{(.*?)}', font_html)

# 获取使用到的字体及其链接
font_dics = {}
for font in font_list:
    # 正则表达式获取字体文件名称
    font_name = re.findall(r'font-family:"PingFangSC-Regular-(.*?)"', font)[0]
    # 正则表达式获取字体文件对应链接
    font_dics[font_name] = 'http:' + re.findall(r',url\("(.*?)"\);', font)[0]

-フォントファイルをローカルにダウンロードする

# 由于我们用到的只有shopNum、tagName和address,这里只下载这三类字体
font_use_list = ['shopNum','tagName','address']
for key in font_use_list:
    woff = requests.get(font_dics[key], headers=headers).content
    with open(f'{key}.woff', 'wb')as f:
        f.write(woff)
  • フォントファイル(ローカルに保存され、FontCreator をインストールしてフォントファイルを開き、フォントコンテンツを表示し、返信FontCreator してインストールパッケージのダウンロードアドレスを取得します)

フォントファイル

2.2.3種類のフォントと実際の文字の間にマッピング関係を作成します

まず、要求されたWebページデータの評価番号のhtmlコンテンツを次のように見てみましょう。

<b>
    <svgmtsi class="shopNum"></svgmtsi>
    <svgmtsi class="shopNum"></svgmtsi>
    <svgmtsi class="shopNum"></svgmtsi>
    <svgmtsi class="shopNum"></svgmtsi>
</b>条评价

対応するページショーのための評価の数4576 レビューは、私たちが対応関係を知って4=&#xf8a1 、5=&#xee4c 、7=&#xe103 、6=&#xe62a 。

FontCreatorを使用 て、次のようにshopNumフォントファイル開きます。

shopNum

比較すると、4はshopNumのuniF8A1に対応し、5はuniEE4C  ...などに対応していることがわかります。したがって、法則を見つけると、&#xf8a1などのデータ要求情報内の対応するデータがわかります。 実際に は、文字(4)のニーズに対応するテキストまたはフォントファイルに対応するuniF8A1実数が可能です。

ここでは、Pythonのフォント処理サードパーティライブラリfontToolsを導入して 、3種類のフォントのマッピング関係を変更する必要があります。

from fontTools.ttLib import TTFont

# 修改三类字体映射关系
real_list = {}
for key in font_use_list:
    # 打开本地字体文件
    font_data = TTFont(f'{key}.woff')
    # font_data.saveXML('shopNum.xml')
    # 获取全部编码,前2个非有用字符去掉 
    uni_list = font_data.getGlyphOrder()[2:]
    # 请求数据中是 "" 对应 编码中为"uniF8A1",我们进行替换,以请求数据为准
    real_list[key] = ['&#x' + uni[3:] for uni in uni_list]

real_list

これらの3種類のフォントファイルを開くと、対応する文字シーケンスが同じであることがわかりました(順序と文字の内容)。次のようにコピーします。

# 字符串
words = '1234567890店中美家馆小车大市公酒行国品发电金心业商司超生装园场食有新限天面工服海华水房饰城乐汽香部利子老艺花专东肉菜学福饭人百餐茶务通味所山区门药银农龙停尚安广鑫一容动南具源兴鲜记时机烤文康信果阳理锅宝达地儿衣特产西批坊州牛佳化五米修爱北养卖建材三会鸡室红站德王光名丽油院堂烧江社合星货型村自科快便日民营和活童明器烟育宾精屋经居庄石顺林尔县手厅销用好客火雅盛体旅之鞋辣作粉包楼校鱼平彩上吧保永万物教吃设医正造丰健点汤网庆技斯洗料配汇木缘加麻联卫川泰色世方寓风幼羊烫来高厂兰阿贝皮全女拉成云维贸道术运都口博河瑞宏京际路祥青镇厨培力惠连马鸿钢训影甲助窗布富牌头四多妆吉苑沙恒隆春干饼氏里二管诚制售嘉长轩杂副清计黄讯太鸭号街交与叉附近层旁对巷栋环省桥湖段乡厦府铺内侧元购前幢滨处向座下澩凤港开关景泉塘放昌线湾政步宁解白田町溪十八古双胜本单同九迎第台玉锦底后七斜期武岭松角纪朝峰六振珠局岗洲横边济井办汉代临弄团外塔杨铁浦字年岛陵原梅进荣友虹央桂沿事津凯莲丁秀柳集紫旗张谷的是不了很还个也这我就在以可到错没去过感次要比觉看得说常真们但最喜哈么别位能较境非为欢然他挺着价那意种想出员两推做排实分间甜度起满给热完格荐喝等其再几只现朋候样直而买于般豆量选奶打每评少算又因情找些份置适什蛋师气你姐棒试总定啊足级整带虾如态且尝主话强当更板知己无酸让入啦式笑赞片酱差像提队走嫩才刚午接重串回晚微周值费性桌拍跟块调糕'

数字の場合(実際には、フォントマップと単語文字列のトップ10にあるのは10個だけです)、登山防止文字&#xf8a1 が実際にはuniF8A1である 場合、最初shopNumで対応する位置を見つけます。次に、同等の文字列を置き換えます。その位置にある単語文字列の文字で十分です。

for i in range(10):
 s.replace(real_list['shopNum'][i], words[i])

漢字タイプ(最大でlen(real_list ['tagName']))の場合、置換ロジックは数値タイプに似ていますが、同じ位置を置き換えるだけです。

for i in range(len(real_list['tagName'])):
    s.replace(real_list['tagName'][i], words[i])

3.単一ページのショップ情報の分析

パート2のフォントアンチクライミングの処理と、直接取得できる店舗情報フィールドを組み合わせることで、すべての店舗情報の分析と収集を完了することができます。ここでは、解析 に正規表現を使用しています。興味のある学生は、xpath、bs4、その他のツールライブラリを使用して処理することもできます。

関数get_items(html、real_list、words)を作成して、すべてのストア情報データを1つのページで取得します 。

# 获取单页全部信息
def get_items(html, real_list, words):    
    # 获取单页全部商铺html整体信息
    shop_list = re.findall(r'<divclass="shop-listJ_shop-listshop-all-list"id="shop-all-list">(.*)<\/div>',html)[0]
    # 获取单页全部商铺html信息组成的列表
    shops = re.findall(r'<liclass="">(.*?)<\/li>', shop_list)
    
    items = []
    for shop in shops:
        # 解析单个商铺信息
        # shop = shops[0]
        item = {}
        # 商铺id(唯一性,用于数据清洗阶段去重)
        item['shop_id'] = re.findall(r'<divclass="txt"><divclass="tit">.*data-shopid="(.*?)"', shop)[0]
        # 商铺名称
        item['shop_name'] = re.findall(r'<divclass="txt"><divclass="tit">.*<h4>(.*)<\/h4>', shop)[0]
        # 商铺星级,由于是二位数,需要除以10.0转化为浮点数
        item['shop_star'] = re.findall(r'<divclass="nebula_star"><divclass="star_icon"><spanclass="starstar_(\d+)star_sml"><\/span>', shop)[0]
        item['shop_star'] = int(item['shop_star'])/10.0
        
        # 其实关于商铺地址信息,在class="operate J_operate Hide"中的data-address是有的
        # 因此,我们不需要用到 字体反爬,直接正则获取吧
        # 商铺地址
        item['shop_address'] = re.findall('<divclass="operateJ_operateHide">.*?data-address="(.*?)"', shop)[0]
        
        shop_name = item['shop_name']
        # 评价数和人均价格,用的是shopNum
        try:
            shop_review = re.findall(r'<b>(.*?)<\/b>条评价', shop)[0]
        except:
            print(f'{shop_name} 无评价数据')
            shop_review = ''
            
        try:
            shop_price = re.findall(r'人均<b>¥(.*?)<\/b>', shop)[0]
        except:
            print(f'{shop_name} 无人均消费数据')
            shop_price = ''
            
        for i in range(10):
            shop_review = shop_review.replace(real_list['shopNum'][i], words[i])
            shop_price = shop_price.replace(real_list['shopNum'][i], words[i])
        # 评价数和人均价格,只取数字,然后组合起来
        item['shop_review'] = ''.join(re.findall(r'\d',shop_review))
        item['shop_price'] = ''.join(re.findall(r'\d',shop_price))
        
        # 商铺所在区域和商铺分类用的是tagName
        shop_tag_site = re.findall(r'<spanclass="tag">.*data-click-name="shop_tag_region_click"(.*?)<\/span>', shop)[0]
        # 商铺分类
        shop_tag_type = re.findall('<divclass="tag-addr">.*?<spanclass="tag">(.*?)</span></a>', shop)[0]
        for i in range(len(real_list['tagName'])):
            shop_tag_site = shop_tag_site.replace(real_list['tagName'][i], words[i])
            shop_tag_type = shop_tag_type.replace(real_list['tagName'][i], words[i])
        # 匹配中文字符的正则表达式: [\u4e00-\u9fa5]
        item['shop_tag_site'] = ''.join(re.findall(r'[\u4e00-\u9fa5]',shop_tag_site))
        item['shop_tag_type'] = ''.join(re.findall(r'[\u4e00-\u9fa5]',shop_tag_type))
        items.append(item)
    
    return items

以下は、スキーを例にとったホームページ上の全店舗の情報データです。

ページ上のすべてのストア情報

4.すべてのページのデータ収集

ほとんどの場合、検索結果は複数ページのデータで構成されています。単一ページのデータを収集することに加えて、すべてのページのデータを取得する必要があります。この場合、通常、最初にページ数を取得してから、ページめくりサイクルを実行してデータのすべてのページをクロールします。

4.1。データページの数を取得します

単一ページのデータの場合、総ページ数はありません。複数ページのデータの場合、ページの下部にドラッグし、最後のページのコントロールを選択して、値が配置されているhtmlノードを見つけてから、通常のデータを使用します。値を取得するための式。

ページ数

# 获取页数
def get_pages(html):
    try:
        page_html = re.findall(r'<divclass="page">(.*?)</div>', html)[0]
        pages = re.findall(r'<ahref=.*>(\d+)<\/a>', page_html)[0]
    except :
        pages = 1
    
    return pages

4.2。すべてのデータを収集する

ウェブページデータの最初のページを解析すると、データページの数を取得し、アンチクライミングフォントをダウンロードし、実際のフォントのreal_listマッピング関係と、実際の文字で構成される文字列ワードを取得できます。同時に、次の情報も取得できます。最初のページのすべてのショップのデータ構成。リスト。次に、2番目のページから最後のページまでトラバースし、取得した単一ページのデータを最初のリストに追加できます。

# 第一页商铺数据构成的列表
shop_data = get_items(html, real_list, words)
# 从第二页开始遍历到最后一页
for page in range(2,pages+1):
    aim_url = f'{url}/p{page}'
    html = get_html(aim_url, headers)
    items = get_items(html, real_list, words)
    shop_data.extend(items)
    print(f'已爬取{page}页数据')
# 转化为dataframe类型
df = pd.DataFrame(shop_data)

取得したすべてのデータで構成されるデータフレームタイプは次のとおりです。

すべての結果

パブリックコメントとフォントの種類のアンチクライミングメカニズムの下で、最初にフォントファイルを取得して、その文字コードに対応する実際の文字マッピング関係を解析し、次にコードを実際の文字に置き換えます。

しかし実際には、Dianpingのショップの情報をクロールするPythonの実際の操作では、確認センターに確認を求めるプロンプトやアカウントのIP制限を求めるプロンプトなど、より複雑な状況が発生する可能性があります。この場合、Cookie、操作を設定します。 IPプロキシの追加などを処理できます。

おすすめ

転載: blog.csdn.net/Python_sn/article/details/112391844