解析煎蛋圖片url的js加載

剛開始學習爬蟲的時候大概了解了一下scrapy,但是后面在工作中并沒有使用scrapy,所以就忘記了大概的用法。最近想重新學習一下scrapy,就想爬一下煎蛋的妹子圖練一下手,但是在實際操作的時候,發現請求返回的內容里面并沒有圖片的鏈接:

<li id="comment-3617895">
  <div>
    <div class="row">
      <div class="author">
        <strong title="防偽碼:8c7a19c8025844512774c2c6103cae3c0e9d9b5f" class="">進擊的肥喵</strong>
        <br>
        <small>
          <a href="#footer" title="@回復" onclick="document.getElementById('comment').value += &#39;@&lt;a href=&quot;//jandan.net/ooxx/page-310#comment-3617895&quot;&gt;進擊的肥喵&lt;/a&gt;: &#39;">@4 hours ago</a>
</span></small></div>
<div class="text">
  <span class="righttext">
    <a >3617895</a>
  </span>
  <p>
    <img src="http://img.jandan.net/img/blank.gif" onload="jandan_load_img(this)"/>
    <span class="img-hash">6fadiP6jpEOinbyOjDMf5F1MT01mhMHpB0oC562st3bqZwhPR+OhO+YvbyrNqKyKMmBNGSDh7Gk0I+B+zcKmrgCm3n1M0bXlNjhOjdDps9/hCO039Uo2+w</span>
  </p>
</div>
<div class="jandan-vote">
  <span class="tucao-like-container">
    <a title="圈圈/支持" href="javascript:;" class="comment-like like" data-id="3617895" data-type="pos">OO</a>
    [<span>45</span>
    ]
                            
  </span>
  <span class="tucao-unlike-container">
    <a title="叉叉/反對" href="javascript:;" class="comment-unlike unlike" data-id="3617895" data-type="neg">XX</a>
    [<span>3</span>
    ]

                            <a href="javascript:;" class="tucao-btn" data-id="3617895">吐槽 [0] </a>
  </span>
</div>
</div></div></li>

但是我們打開控制面板后,可以看到圖片的url

main_page.png

所以我一開始以為它是異步加載的,但是查看網絡傳輸的時候并沒有看到它后續請求,所以就想著圖片的地址會不會已經在返回的頁面里,只是后續通js把它解析出來,所以再次回到返回的頁面查看,發現了一個比較重要的東西,img-hash:

<p>
    <img src="http://img.jandan.net/img/blank.gif" onload="jandan_load_img(this)"/>
    <span class="img-hash">6fadiP6jpEOinbyOjDMf5F1MT01mhMHpB0oC562st3bqZwhPR+OhO+YvbyrNqKyKMmBNGSDh7Gk0I+B+zcKmrgCm3n1M0bXlNjhOjdDps9/hCO039Uo2+w</span>
  </p>

可以看出它一開始是一個空白的圖片,然后在onload的時候會調用jandan_load_img方法加載圖片,而img-hash就很有可能保存著圖片的url

然后全局搜索jandan_load_img這個方法,可以發現它在一個js里面:http://cdn.jandan.net/static/min/xxxxxxxxxxxxxxxxxxxxxxx.js(在實際操作中名字不一定相同,但是路徑都是一樣的)。我們對這個函數下斷點:

jandan_load_img.png

可以看到e就是img-hash,經過S45fAAhlWwSoItVgdyMFW4jIPId52kxV方法調用后返回的就是圖片的url,我們再看一下這個函數:

function S45fAAhlWwSoItVgdyMFW4jIPId52kxV(n, k, x, f) {
  var k = k ? k : "DECODE";
  var x = x ? x : "";
  var f = f ? f : 0;
  var g = 4;
  x = md5(x);
  var w = md5(x.substr(0, 16));
  var u = md5(x.substr(16, 16));
  if (g) {
    if (k == "DECODE") {
      var t = n.substr(0, g)
    } else {
      var b = md5(microtime());
      var d = b.length - g;
      var t = b.substr(d, g)
    }
  } else {
    var t = ""
  }
  var r = w + md5(w + t);
  var m;
  if (k == "DECODE") {
    n = n.substr(g);
    m = base64_decode(n)
  } else {
    f = f ? f + time() : 0;
    tmpstr = f.toString();
    if (tmpstr.length >= 10) {
      n = tmpstr.substr(0, 10) + md5(n + u).substr(0, 16) + n
    } else {
      var e = 10 - tmpstr.length;
      for (var p = 0; p < e; p++) {
        tmpstr = "0" + tmpstr
      }
      n = tmpstr + md5(n + u).substr(0, 16) + n
    }
    m = n
  }
  var h = new Array(256);
  for (var p = 0; p < 256; p++) {
    h[p] = p
  }
  var q = new Array();
  for (var p = 0; p < 256; p++) {
    q[p] = r.charCodeAt(p % r.length)
  }
  for (var o = p = 0; p < 256; p++) {
    o = (o + h[p] + q[p]) % 256;
    tmp = h[p];
    h[p] = h[o];
    h[o] = tmp
  }
  var l = "";
  m = m.split("");
  for (var v = o = p = 0; p < m.length; p++) {
    v = (v + 1) % 256;
    o = (o + h[v]) % 256;
    tmp = h[v];
    h[v] = h[o];
    h[o] = tmp;
    l += chr(ord(m[p]) ^ (h[(h[v] + h[o]) % 256]))
  }
  if (k == "DECODE") {
    if ((l.substr(0, 10) == 0 || l.substr(0, 10) - time() > 0) && l.substr(10, 16) == md5(l.substr(26) + u).substr(0, 16)) {
      l = l.substr(26)
    } else {
      l = ""
    }
  } else {
    l = base64_encode(l);
    var c = new RegExp("=","g");
    l = l.replace(c, "");
    l = t + l
  }
  return l
}

這個函數除了將hash值解析出url(DECODE)之外,似乎還可以將進行加密操作(ENCODE),但是我只需要解密部分的功能,所以在重寫的時候只需要實現解密部分的功能就好了

python實現如下:

# 由于函數的x是會更新的,所以這里原來的代碼不通用,具體請看下面的實現

更新

decrypt()方法中的x參數更新了:

image.png

當初測試時在兩個新的會話中,x的值是一樣的,所以我就以為它是不變的,但是現在看來它是會周期性更新,所以需要從js中匹配出它的值_pat = re.compile('f\.remove\(\);var c=.+?\(e,"(.+?)"\)'),js地址可以從html中解析出。

js.png

# python2 & python3

import base64
import re
import requests
import sys

from hashlib import md5
from lxml import etree

_pat_x = re.compile('f\.remove\(\);var c=.+?\(e,"(.+?)"\)')

if sys.version_info[0] == 2:  # python2
    to_int = ord
else:  # python3
    to_int = int

page_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': 'en-US,en;q=0.8',
    'Host': 'jandan.net',
    'Upgrade-Insecure-Requests': '1',
    'Referer': 'http://jandan.net',
    'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36',
}

js_headers = {
    'Accept': '*/*',
    'Accept-Encoding': 'gzip, deflate',
    'Accept-Language': 'en-US,en;q=0.8',
    'Host': 'cdn.jandan.net',
    'Referer': 'http://jandan.net',
    'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36',
}


def decrypt(n, x):
    """
    :param n: img-hash
    :param x: x from js
    :return:
    """
    g = 4
    x = md5(x.encode('utf8')).hexdigest()
    w = md5(x[:16].encode('utf8')).hexdigest()
    u = md5(x[16:].encode('utf8')).hexdigest()

    t = n[:g]
    r = w + md5((w + t).encode('utf8')).hexdigest()

    n = n[g:]
    m = base64.b64decode(n + (4 - len(n) % 4) * '=')

    h = list(range(256))
    q = [ord(r[i % 64]) for i in range(256)]
    o = 0
    for p in range(256):
        o = (o + h[p] + q[p]) & 0xFF
        h[p], h[o] = h[o], h[p]

    l = ''
    v = 0
    o = 0
    for p in m:
        v = (v + 1) & 0xFF
        o = (o + h[v]) & 0xFF
        h[v], h[o] = h[o], h[v]
        l += chr(to_int(p) ^ (h[(h[v]+h[o]) & 0xFF]))
    l = l[26:]
    if not l.startswith('http:'):
        l = 'http:' + l
    return l


def get_x(js_url):
    """
    :param js_url: js_url from page
    :return:
    """
    js = requests.get(js_url, js_headers)
    x = _pat_x.search(js.text).group(1)
    return x


def request_url(url):
    resp = requests.get(url, headers=page_headers)
    doc = etree.HTML(resp.content)
    js_url = doc.xpath('//script[contains(@src, "cdn.jandan.net/static/min")]/@src')[0]
    if not js_url.startswith('http:'):
        js_url = 'http:' + js_url
    x = get_x(js_url)

    hash_images = doc.xpath('//*[@class="img-hash"]/text()')
    image_urls = []
    for item in hash_images:
        url = decrypt(item, x)
        image_urls.append(url)
    return image_urls


if __name__ == '__main__':
    image_urls = request_url('http://jandan.net/ooxx')
    for url in image_urls:
        print(url)
image.png
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,936評論 6 535
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,744評論 3 421
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,879評論 0 381
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,181評論 1 315
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,935評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,325評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,384評論 3 443
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,534評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,084評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,892評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,067評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,623評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,322評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,735評論 0 27
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,990評論 1 289
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,800評論 3 395
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,084評論 2 375

推薦閱讀更多精彩內容