解析煎蛋图片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 href="//jandan.net/ooxx/page-310#comment-3617895">3617895</a>
  </span>
  <p>
    <img src="//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="//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阅读 194,491评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,856评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,745评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,196评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,073评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,112评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,531评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,215评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,485评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,578评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,356评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,215评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,583评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,898评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,174评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,497评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,697评论 2 335

推荐阅读更多精彩内容