Python爬虫類の卵焼き網妹図爬虫類、解読画像リンク暗号化方式

21149 ワード

以前、魚Cフォーラムの時、多くの人がPythonで爬虫類の卵焼き網の妹の図を書いているのを見て、その時私も書いたことがあります.多くの妹の写真を登りました.その後、卵焼き網は妹の図のホームページを改善し、画像のアドレスを暗号化したので、フォーラムの中の人はよくどのように要求したページにリンクがないかと聞かれます.この文章では、オムレツネットOOXX妹図のリンク取得方法について説明します.
まず、これまで卵焼き網が反爬虫機構を増やしたのは、多くの人がサイトに登ったからだと説明します.爬虫類の頻繁なアクセスはサイトにストレスを与えるので、爬虫類の簡単な運行が成功したら適当に止めて、他人のものに過度に登らないことをお勧めします.
爬虫類の考え方分析
画像ダウンロードフローチャート
まず、簡単なフローチャート(非規範フローチャートフォーマット)を使用して、簡単なネットワークに登った妹図のフロー全体を示します.
フローチャート解読
1、卵焼きのネットの妹の図を登って、私达はまず任意の1つの妹の図のページを开けて、例えばhttp://jandan.net/ooxx/page-44#comments次に、このページを要求して、2つの重要な情報(後述する情報の具体的な役割)を取得する必要があります.このうち、最初の情報は、各妹の画像のhash値であり、これは、画像アドレスを生成するための重要な情報を復号するために使用されます.
2、ページにはピクチャを抽出するhashのほかに、現在のページに抽出された重要なjsファイルのアドレスがあり、このjsファイルには同様にピクチャアドレスを生成するための重要なパラメータが含まれている.このパラメータを得るには、このJSアドレスを要求しなければならない.当時、妹図の各ページのjsアドレスは異なるので、ページから抽出する必要がある.
3、ピクチャのhashとjsのキーパラメータを得た後、jsで提供される復号方式に従ってピクチャのリンクを得ることができ、この復号方式はPythonコードとjsコードの参照で説明する.
4、写真のリンクがあれば、写真をダウンロードするのはあまり言わないで、后で第2の文章があって、マルチスレッド+マルチプロセスの方式を使って画像をダウンロードします.
ページ解析
Webソースの解読
妹図のページを開くことができますか?それとも最初のページですか?http://jandan.net/ooxx/page-44#comments例として、ソースコード(レビュー要素ではなく)を表示すると、ピクチャアドレスを置くべき場所にピクチャアドレスがなく、次のコードに似ていることがわかります.
<p><img src="//img.jandan.net/img/blank.gif" onload="jandan_load_img(this)" /><span class="img-hash">ece8ozWUT/VGGxW1hlbITPgE0XMZ9Y/yWpCi5Rz5F/h2uSWgxwV6IQl6DAeuFiT9mH2ep3CETLlpwyD+kU0YHpsHPLnY6LMHyIQo6sTu9/UdY5k+Vjt3EQspan>p>

このコードから、ピクチャアドレスはjs関数に置き換えられていることがわかります.すなわち、ピクチャアドレスはこのjandan_load_img(this)関数によって取得され、ロードされているので、JSファイルでこの関数の意味を検索する必要があります.
jsファイル解読
各jsファイルでjandan_load_imgを検索することによって、最後に1つのアドレスで類似することができる.http://cdn.jandan.net/static/min/1d694f08895d377af4835a24f06090d0.29100001.jsのファイルの中でこの関数の定義を探し当てて、圧縮したJSコードをフォーマットして見て、具体的な定義は以下の断片を見ることができます:
function jandan_load_img(b) {
    var d = $(b);
    var f = d.next("span.img-hash");
    var e = f.text();
    f.remove();
    var c = f_Qa8je29JONvWCrmeT1AJocgAtaiNWkcN(e, "agC37Is2vpAYzkFI9WVObFDN5bcFn1Px");

このコードの意味は分かりやすく、まず現在のラベルの下にあるcssがimg-hashのspanラベルのテキスト、つまり私たちが最初に言った画像のhash値を抽出しました.そして、この値を1つの文字列パラメータ(各ページのこのパラメータは変動し、このページはagC37Is2vpAYzkFI9WVObFDN5bcFn1Px)とともに別の関数f_Qa8je29JONvWCrmeT1AJocgAtaiNWkcNに渡すので、この関数の意味を確認しなければなりません.この関数はピクチャリンクを生成するための関数です.
f_ 関数の解読
jsでこのf_を検索できます関数の定義は、2つ見られますが、大丈夫です.コードが上から下まで実行される法則に基づいて、私たちは比較的後ろのものを見るだけでいいです.完全な内容は以下の通りです.
var f_Qa8je29JONvWCrmeT1AJocgAtaiNWkcN = function(m, r, d) {
    var e = "DECODE";
    var r = r ? r : "";
    var d = d ? d : 0;
    var q = 4;
    r = md5(r);
    var o = md5(r.substr(0, 16));
    var n = md5(r.substr(16, 16));
    if (q) { if (e == "DECODE") { var l = m.substr(0, q) } } else { var l = "" }
    var c = o + md5(o + l);
    var k;
    if (e == "DECODE") {
        m = m.substr(q);
        k = base64_decode(m)
    }
    var h = new Array(256);
    for (var g = 0; g < 256; g++) { h[g] = g }
    var b = new Array();
    for (var g = 0; g < 256; g++) { b[g] = c.charCodeAt(g % c.length) }
    for (var f = g = 0; g < 256; g++) {
        f = (f + h[g] + b[g]) % 256;
        tmp = h[g];
        h[g] = h[f];
        h[f] = tmp
    }
    var t = "";
    k = k.split("");
    for (var p = f = g = 0; g < k.length; g++) {
        p = (p + 1) % 256;
        f = (f + h[p]) % 256;
        tmp = h[p];
        h[p] = h[f];
        h[f] = tmp;
        t += chr(ord(k[g]) ^ (h[(h[p] + h[f]) % 256]))
    }
    if (e == "DECODE") { if ((t.substr(0, 10) == 0 || t.substr(0, 10) - time() > 0) && t.substr(10, 16) == md5(t.substr(26) + n).substr(0, 16)) { t = t.substr(26) } else { t = "" } }
    return t
};

この関数は3つのパラメータを渡す必要があります.最初のパラメータはピクチャのhash値で、2番目のパラメータはjandan_load_img関数で見た文字列です.3番目のパラメータは実際には役に立ちません.jandan_load_img関数にはまったく伝わっていないからです.私たちはJSコードの意味でこの関数をPythonコードに書き換えるだけでいいです.
Python書き換え関数
Pythonを使ってf_関数を書き換えると、次のようになります.
def get_imgurl(m, r='', d=0):
    '''        '''
    e = "DECODE"
    q = 4
    r = _md5(r)
    o = _md5(r[0:0 + 16])
    n = _md5(r[16:16 + 16])
    l = m[0:q]
    c = o + _md5(o + l)
    m = m[q:]
    k = _base64_decode(m)
    h = list(range(256))
    b = [ord(c[g % len(c)]) for g in range(256)]

    f = 0
    for g in range(0, 256):
        f = (f + h[g] + b[g]) % 256
        tmp = h[g]
        h[g] = h[f]
        h[f] = tmp

    t = ""
    p, f = 0, 0
    for g in range(0, len(k)):
        p = (p + 1) % 256
        f = (f + h[p]) % 256
        tmp = h[p]
        h[p] = h[f]
        h[f] = tmp
        t += chr(k[g] ^ (h[(h[p] + h[f]) % 256]))
    t = t[26:]
    return t

この関数は他の2つの関数を使用する必要があります.1つ目はMD 5暗号化の関数で、この関数はJSのこのような段落に対応しています.
var o = md5(r.substr(0, 16));

jsのsubstr()関数は実はPythonの中のスライスの使い方で、定義を少し見ればわかりますが、説明しません.
MD 5の暗号化をPythonバージョンに変換すると、次のようになります.
def _md5(value):
    '''md5  '''
    m = hashlib.md5()
    m.update(value.encode('utf-8'))
    return m.hexdigest()

次に、jsのセグメントで使用されるbash 64の復号関数があります.
k = base64_decode(m)

Pythonを使用する場合は注意が必要ですが、Pythonのbase64.b64decodeをそのまま使用するとエラーが発生します.具体的なエラー内容は:
binascii.Error: Incorrect padding

データを復号する前に、具体的な関数は次のとおりです.
def _base64_decode(data):
    '''bash64  ,             '''
    missing_padding = 4 - len(data) % 4
    if missing_padding:
        data += '=' * missing_padding
    return base64.b64decode(data)

ここでは,ピクチャリンクを取得する関数が完成し,主に3つの関数を用いる.
Webページからコピーした2つのパラメータをこの関数に入力してテストします.
m = 'ece8ozWUT/VGGxW1hlbITPgE0XMZ9Y/yWpCi5Rz5F/h2uSWgxwV6IQl6DAeuFiT9mH2ep3CETLlpwyD+kU0YHpsHPLnY6LMHyIQo6sTu9/UdY5k+Vjt3EQ'
r = 'HpRB2OSft5RhlSyZaXV8xYpvEAgDThcA'
print(get_imgurl(m,r))

次の出力が表示されます.
//ww3.sinaimg.cn/mw600/0073ob6Pgy1fpet9wku7dj30hs0qljuz.jpg

注意:ここでrパラメータは各ページのjsからコピーされ、各ページのjsアドレスは変動し、このパラメータも変動します.
hashアドレスとjsアドレスの取得
前述したようにhash値はピクチャアドレスを取得するキーパラメータであり、他のパラメータはjsファイルにあり、このjsファイルはページごとに異なるので、この2つのキーパラメータを抽出します.
一括取得hash
画像のhash値を取得するのは便利です.BeautifulSoupの方法を使用すればいいです.具体的なコードクリップは:
def get_urls(url):
    '''              '''
    headers = {
        'user-agent': 'Mozilla/5.0 (Windows NT 6.3; Win64; x64; rv:47.0) Gecko/20100101 Firefox/47.0',
        'Host': 'jandan.net'
    }
    html = requests.get(url, headers=headers).text
    js_url = 'http:' + re.findall('', html)[-1]
    _r = get_r(js_url)
    soup = BeautifulSoup(html, 'lxml')
    tags = soup.select('.img-hash')
    for tag in tags:
        img_hash = tag.text
        img_url = get_imgurl(img_hash,_r)
        print(img_url)

hashを するコードは、 の です.
soup = BeautifulSoup(html, 'lxml')
    tags = soup.select('.img-hash')
    for tag in tags:
        img_hash = tag.text

jsのキー の
jsアドレスを する は、 です.
js_url = 'http:' + re.findall('', html)[-1]

ここで したいのは、 は1つのリストなので、 にリストの の1つのリンクを る があります. てみると、このようなJSファイルが2つあるページがあり、1つは されているので、 の1つを します.この はリストインデックスで[-1]を して の1つを します.
jsアドレスを した 、 が になり、キー が つかります. には、 として くことができます.
def get_r(js_url):
    '''       '''
    js = requests.get(js_url).text
    _r = re.findall('c=f_[\w\d]+\(e,"(.*?)"\)', js)[0]
    return _r

なコード
は、1つのページのすべてのピクチャリンクの なコードを します.
# -*- coding: utf-8 -*-
import requests
from bs4 import BeautifulSoup
import hashlib
import re
import base64


def _md5(value):
    '''md5  '''
    m = hashlib.md5()
    m.update(value.encode('utf-8'))
    return m.hexdigest()


def _base64_decode(data):
    '''bash64  ,             '''
    missing_padding = 4 - len(data) % 4
    if missing_padding:
        data += '=' * missing_padding
    return base64.b64decode(data)


def get_imgurl(m, r='', d=0):
    '''        '''
    e = "DECODE"
    q = 4
    r = _md5(r)
    o = _md5(r[0:0 + 16])
    n = _md5(r[16:16 + 16])
    l = m[0:q]
    c = o + _md5(o + l)
    m = m[q:]
    k = _base64_decode(m)
    h = list(range(256))
    b = [ord(c[g % len(c)]) for g in range(256)]

    f = 0
    for g in range(0, 256):
        f = (f + h[g] + b[g]) % 256
        tmp = h[g]
        h[g] = h[f]
        h[f] = tmp

    t = ""
    p, f = 0, 0
    for g in range(0, len(k)):
        p = (p + 1) % 256
        f = (f + h[p]) % 256
        tmp = h[p]
        h[p] = h[f]
        h[f] = tmp
        t += chr(k[g] ^ (h[(h[p] + h[f]) % 256]))
    t = t[26:]
    return t


def get_r(js_url):
    '''       '''
    js = requests.get(js_url).text
    _r = re.findall('c=f_[\w\d]+\(e,"(.*?)"\)', js)[0]
    return _r


def get_urls(url):
    '''              '''
    headers = {
        'user-agent': 'Mozilla/5.0 (Windows NT 6.3; Win64; x64; rv:47.0) Gecko/20100101 Firefox/47.0',
        'Host': 'jandan.net'
    }
    html = requests.get(url, headers=headers).text
    js_url = 'http:' + re.findall('', html)[-1]
    _r = get_r(js_url)
    soup = BeautifulSoup(html, 'lxml')
    tags = soup.select('.img-hash')
    for tag in tags:
        img_hash = tag.text
        img_url = get_imgurl(img_hash,_r)
        print(img_url)


if __name__ == '__main__':
    get_urls('http://jandan.net/ooxx/page-44')

のコードを すると、このページのすべての リンクを できます. のリンクは の りです.
//ww3.sinaimg.cn/mw600/0073ob6Pgy1fpet9wku7dj30hs0qljuz.jpg
//ww3.sinaimg.cn/mw600/0073tLPGgy1fpet9mszjwj30hs0g1jsv.jpg
//ww3.sinaimg.cn/mw600/0073ob6Pgy1fpesskkgobj31jk1jkk5b.jpg
//wx3.sinaimg.cn/mw600/006XfbArly1fpesq2jn1vj30j60svaz3.jpg
//wx3.sinaimg.cn/mw600/6967abd2gy1fpenoyobrcj20u03d0b2d.jpg
//wx3.sinaimg.cn/mw600/6967abd2gy1fpenp38v9uj20u03zkhdy.jpg

まとめ:ここまで、 き の の リンクを する はすでに てきましたが、 はマルチスレッド+マルチプロセスで をダウンロードすることについてお しします.
:http://www.tendcode.com/article/jiandan-meizi-spider/