解析某電影和某招聘網(wǎng)站的web-font自定義字體

貓眼電影

如果試圖有人采集過貓眼電影的票房數(shù)據(jù)杠茬,就會發(fā)現(xiàn)它的關鍵字段是加密的。
打開瀏覽器的控制面板宁赤,就會發(fā)現(xiàn)雖然在前端是人眼可識別的栓票,但是在網(wǎng)頁源代碼里面卻不是正常的數(shù)字,可見它們是被加密了。

element.png
source.png

可以通過返回的網(wǎng)頁源代碼看到厉斟,3105.65在網(wǎng)頁源代碼里是.擦秽,其中0對應著,這樣對于爬蟲而言是無法處理的感挥,所以需要解析出真正的數(shù)字

解決方法

我們可以看到class名字是stonefont触幼,這是一個自定義字體,我們可以在返回的頁面里面找到這個字體資源的地址

font.png

如果可以將字體和數(shù)值一一對應那么就可以解決問題了堂鲤,那么媒峡,如何通過python實現(xiàn)?答案就是一個有關字體的模塊:fonttools

from fontTools.ttLib import TTFont

font_maoyan = TTFont('maoyan.woff')
font_maoyan.saveXML('maoyan.xml')

通過saveXML()方法可以把字體資源保存在xml文件中半哟,打開xml文件寓涨,可以發(fā)現(xiàn)下面的內(nèi)容

<GlyphOrder>
  <!-- The 'id' attribute is only for humans; it is ignored when parsed. -->
  <GlyphID id="0" name="glyph00000"/>
  <GlyphID id="1" name="x"/>
  <GlyphID id="2" name="uniF07E"/>
  <GlyphID id="3" name="uniED44"/>
  <GlyphID id="4" name="uniE41D"/>
  <GlyphID id="5" name="uniE26D"/>
  <GlyphID id="6" name="uniF391"/>
  <GlyphID id="7" name="uniEE67"/>
  <GlyphID id="8" name="uniF83E"/>
  <GlyphID id="9" name="uniED3B"/>
  <GlyphID id="10" name="uniF5A0"/>
  <GlyphID id="11" name="uniE080"/>
</GlyphOrder>

如果通過瀏覽器對比贱田,可以發(fā)現(xiàn),0對應&#xf07e;蔬墩,1對應&#xed44;耗拓,...,9對應&#xe080;樟插,正好和上圖對應上了竿刁,而這個其實可以通過getGlyphOrder()方法的到食拜。

print(font_maoyan.getGlyphOrder())
# ['glyph00000', 'x', 'uniF07E', 'uniED44', 'uniE41D', 'uniE26D', 'uniF391', 'uniEE67', 'uniF83E', 'uniED3B', 'uniF5A0', 'uniE080']

所以我們在請求頁面之后,解析出字體資源的鏈接流强,然后再請求字體資源,解析出字符的映射關系队腐,最后再把請求頁面替換成源字符即可奏篙。我們可以把字體資源的結(jié)果緩存起來,如果緩存中有的話悠就,就直接返回充易,如果沒有,就請求資源在解析炸茧。

python實現(xiàn)

import re
import requests

from cStringIO import StringIO
from fontTools.ttLib import TTFont

_pat_font_url = re.compile("'(//vfile.meituan.net/colorstone/([0-9a-f]{32}).+?woff)'")
_pat_font = re.compile('&#x[0-9a-f]{4};')

maps = {}


headers = {
    'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8',
    'Accept-Encoding': 'gzip, deflate',
    'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8,zh-TW;q=0.7',
    'Host': 'maoyan.com',
    'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36',
}


def get_font_regx(digest, font_url):
    if digest in maps:  # 緩存
        return maps[digest]
    resp = requests.get(font_url)
    font = TTFont(StringIO(resp.content))
    mappings = {'&#x{};'.format(k[3:].lower()): str(idx) for idx, k in enumerate(font.getGlyphOrder()[2:])}  # 生成映射關系

    def callback(regx):  # 替換策略
        return mappings.get(regx.group(0), regx.group(0))
    maps[digest] = callback
    return callback

if __name__ == '__main__':
    resp = requests.get('http://maoyan.com/', headers=headers)
    url, digest = _pat_font_url.search(resp.text).groups()
    font_url = 'http:' + url
    callback = get_font_regx(digest, font_url)
    text = _pat_font.sub(callback, resp.text)
    print(text)

實習僧

上面的網(wǎng)站只有數(shù)字被替換了梭冠,比較容易處理改备,但是這個網(wǎng)站就不一樣了,里面還有一些漢字也被替換了:


front.png
<div class="list">
  <div class="po-name">
    <div class="names cutom_font">
      <a href="/intern/inn_ywdtbpiwtwcp" target="_blank">&#xf3b1&#xf157&#xe7e6&#xe9f3&#xeba7&#xe59e&#xee74&#xf423&#xec73(實習)</a></div>
    <div class="part">
      <a class="cutom_font" href="/com/com_eknouhdxcyqb" target="_blank">看見音樂</a>- Python</div></div>
  <div class="po-detail">
    <div class="addr">
      <img src="https://sxsimg.xiaoyuanzhao.com/static/new_main/img/img_10.png?v=d48ec07cec9ddecce51147cecd216171" />
      <span>上海</span></div>
    <div class="xz">
      <img src="https://sxsimg.xiaoyuanzhao.com/static/new_main/img/img_17.png?v=fac8e686636c06166246f62531a07b56" />
      <span class="cutom_font">
        <i class="money"></i>&#xf123&#xe8ba&#xe8ba-&#xf123&#xe72f&#xe8ba/天</span>
      <span class="line">|</span>
      <img src="https://sxsimg.xiaoyuanzhao.com/static/new_main/img/img_19.png?v=2f3bd39eae1f92a6852388ff53e2f5e7" />
      <span class="cutom_font">&#xe5ee天/周</span>
      <span class="line">|</span>
      <img src="https://sxsimg.xiaoyuanzhao.com/static/new_main/img/img_21.png?v=c6726c9ad768ef881bb73ec1dba5e120" />
      <span class="cutom_font">&#xe5ee個月</span></div>
  </div>
  <div class="com-logo">
    <a href="/com/com_eknouhdxcyqb" target="_blank">
      <img src="https://sxsimg.xiaoyuanzhao.com/46/F9/46ACA43D16FD1A878A5114184CEE9DF9.png" alt="看見音樂實習招聘" /></a>
  </div>
</div>

如果我們像之前那樣那樣操作,發(fā)現(xiàn)GlyphOrder沒有什么有用的內(nèi)容:

<GlyphOrder>
    <!-- The 'id' attribute is only for humans; it is ignored when parsed. -->
    <GlyphID id="0" name="glyph00000"/>
    <GlyphID id="1" name="x"/>
    <GlyphID id="2" name="uni30"/>
    <GlyphID id="3" name="uni31"/>
    <GlyphID id="4" name="uni32"/>
    <GlyphID id="5" name="uni33"/>
    <GlyphID id="6" name="uni34"/>
    <GlyphID id="7" name="uni35"/>
    <GlyphID id="8" name="uni36"/>
    <GlyphID id="9" name="uni37"/>
    <GlyphID id="10" name="uni38"/>
    <GlyphID id="11" name="uni39"/>
    <GlyphID id="12" name="uni4E00"/>
    ...
</GlyphOrder>

其實通過注釋可以看到碉渡,id只是顯示字符的順序滞诺,并不是它所代表的字符环疼,貓眼里面也是這樣。但是我們可以在另一個結(jié)構(gòu)里面找到答案:

<cmap_format_4 platformID="0" platEncID="3" language="0">
  <map code="0x78" name="x"/><!-- LATIN SMALL LETTER X -->
  <map code="0xe040" name="uni45"/><!-- ???? -->
  <map code="0xe053" name="uni6b"/><!-- ???? -->
  <map code="0xe0d3" name="uni53"/><!-- ???? -->
  <map code="0xe103" name="uni42"/><!-- ???? -->
  <map code="0xe21a" name="uni57"/><!-- ???? -->
  <map code="0xe21f" name="uni4E00"/><!-- ???? -->
  <map code="0xe231" name="uni38"/><!-- ???? -->
  <map code="0xe253" name="uni5a"/><!-- ???? -->
  <map code="0xe25a" name="uni5E7F"/><!-- ???? -->
  <map code="0xe272" name="uni77"/><!-- ???? -->
  <map code="0xe2c3" name="uni4c"/><!-- ???? -->
  ...
</cmap_format_4>

比較了幾個之后可以發(fā)現(xiàn)淋叶,&#xe32e對應1,它的unicode編碼是\u0031等限,&#xe25a對應,它的unicode編碼是\u5e7f望门,和上面能夠正確對應。而這個映射關系可以通過getBestCmap()得到筹误,因此我們的實現(xiàn)厨剪,只要稍微修改之前的代碼即可。

font = TTFont('shixiseng.woff')
font.getBestCmap()
{120: 'x',
 57408: 'uni45',
 57427: 'uni6b',
 57555: 'uni53',
 57603: 'uni42',
 57882: 'uni57',
 57887: 'uni4E00',
 57905: 'uni38',
 57939: 'uni5a',
 57946: 'uni5E7F',
 57970: 'uni77',
 58051: 'uni4c',
 58080: 'uni4b',
...
}

python實現(xiàn)

import re
import requests

from cStringIO import StringIO
from fontTools.ttLib import TTFont

_pat_font_content = re.compile('myFont; src: url\("data:application/octet-stream;base64,(.+?)"')
_pat_font = re.compile('&#x[0-9a-f]{4}')

maps = {}


headers = {
    'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8',
    'Accept-Encoding': 'gzip, deflate',
    'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8,zh-TW;q=0.7',
    'Host': 'www.shixiseng.com',
    'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36',
}


def get_font_regx(content):
    if content in maps:
        return maps[content]
    ctx = content.decode('base64')
    font = TTFont(StringIO(ctx))
    mappings = {}
    for k, v in font.getBestCmap().items():
        if v.startswith('uni'):
            mappings['&#x{:x}'.format(k)] = unichr(int(v[3:], 16))
        else:
            mappings['&#x{:x}'.format(k)] = v

    def callback(regx):
        return mappings.get(regx.group(0), regx.group(0))
    maps[content] = callback
    return callback

if __name__ == '__main__':
    resp = requests.get('https://www.shixiseng.com/interns?k=python&p=1', headers=headers)
    content = _pat_font_content.search(resp.text).group(1)
    callback = get_font_regx(content)
    text = _pat_font.sub(callback, resp.text)
    print(text)
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市搀军,隨后出現(xiàn)的幾起案子勇皇,更是在濱河造成了極大的恐慌,老刑警劉巖敛摘,帶你破解...
    沈念sama閱讀 216,744評論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件兄淫,死亡現(xiàn)場離奇詭異,居然都是意外死亡氓润,警方通過查閱死者的電腦和手機薯鳍,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,505評論 3 392
  • 文/潘曉璐 我一進店門挖滤,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人斩松,你說我怎么就攤上這事∪樾遥” “怎么了?”我有些...
    開封第一講書人閱讀 163,105評論 0 353
  • 文/不壞的土叔 我叫張陵符欠,是天一觀的道長瓶埋。 經(jīng)常有香客問我养筒,道長,這世上最難降的妖魔是什么晕粪? 我笑而不...
    開封第一講書人閱讀 58,242評論 1 292
  • 正文 為了忘掉前任兵多,我火速辦了婚禮,結(jié)果婚禮上剩膘,老公的妹妹穿的比我還像新娘怠褐。我一直安慰自己,他們只是感情好奈懒,可當我...
    茶點故事閱讀 67,269評論 6 389
  • 文/花漫 我一把揭開白布磷杏。 她就那樣靜靜地躺著,像睡著了一般慈格。 火紅的嫁衣襯著肌膚如雪遥金。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,215評論 1 299
  • 那天选泻,我揣著相機與錄音,去河邊找鬼梯捕。 笑死窝撵,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播蝌矛,決...
    沈念sama閱讀 40,096評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼入撒,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了茅逮?” 一聲冷哼從身側(cè)響起献雅,我...
    開封第一講書人閱讀 38,939評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎侯谁,沒想到半個月后章钾,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,354評論 1 311
  • 正文 獨居荒郊野嶺守林人離奇死亡惨撇,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,573評論 2 333
  • 正文 我和宋清朗相戀三年魁衙,在試婚紗的時候發(fā)現(xiàn)自己被綠了椰棘。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,745評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡祷蝌,死狀恐怖帆卓,靈堂內(nèi)的尸體忽然破棺而出米丘,到底是詐尸還是另有隱情糊啡,我是刑警寧澤,帶...
    沈念sama閱讀 35,448評論 5 344
  • 正文 年R本政府宣布堕扶,位于F島的核電站稍算,受9級特大地震影響役拴,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜河闰,卻給世界環(huán)境...
    茶點故事閱讀 41,048評論 3 327
  • 文/蒙蒙 一姜性、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧汞贸,春花似錦印机、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,683評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至初嘹,卻和暖如春沮趣,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,838評論 1 269
  • 我被黑心中介騙來泰國打工温眉, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留翁狐,地道東北人。 一個月前我還...
    沈念sama閱讀 47,776評論 2 369
  • 正文 我出身青樓,卻偏偏與公主長得像懈词,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,652評論 2 354

推薦閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,085評論 25 707
  • 發(fā)現(xiàn) 關注 消息 iOS 第三方庫、插件秧秉、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關注 2017.06.26 09:4...
    肇東周閱讀 12,096評論 4 62
  • 你來了象迎,在二月 記憶中的桃花雪 匯集成眼前輕柔飄動的海子 隨桃花雪一起來的還有你 你的到來 足以構(gòu)成一個完美的世界...
    bxcyml冰心閱讀 236評論 0 1
  • 寒冷冬天的到來給了Snail先生很多靈感砾淌。 Snail先生喜歡手捧著手機在衛(wèi)生間里待上很久。家里的衛(wèi)生間的玻璃窗邊...
    懷曇憶蝶閱讀 370評論 0 1
  • 親愛的赃春,離開你已有兩月劫乱。雖然不能日日相守,但每每能在電話里聽到你的聲音衷戈。當我知道你為我日日擔心時伏伯,我是多么慶幸有你...
    523aa44f6726閱讀 418評論 0 1