Python抓取花瓣网画板图片

功能区
 taochengwei   python  python  爬虫   2016-11-30   百度主动推送失败
正文区

################################################################

代码库:https://github.com/staugur/grab_huaban_board/releases/tag/v1.0

Python抓取花瓣网“画板”的图片,程序稍简陋,后续并发执行(也适用并发)。

发现规律:

1. 画板(board)的title中包含了此画板所有图片(pin),可以获取到关键信息——画板数量。

2. 除了首屏的图片外,往下滚动,动态加载时,采用ajax,F12查看Network,发现请求了画板URL+/?iw538bzd&max=916733010&limit=20&wfl=1,其中max是当前展现的最后一个图片的pin id,limit是ajax刷新后的图片数量。

3. pin的URL是http://huaban.com/pins/+pin,可以查看具体大图,查看其HTML源码,能发现以下信息:

app["page"] = {"$url":"/pins/939351949/", "pin":{"pin_id":939351949, "user_id":9880671, "board_id":32956845, "file_id":122346806, "file":{"bucket":"hbimg", "key":"591ba6953c5912c9d82272b9cc575fe1b04fbe9919a01-tKc4ku", "type":"image/jpeg", "height":"640", "width":"640", "frames":"1"}

这里的规律是以空格为分割,倒数第八段基本是以上代码开端。

实现思路:

根据两个规律可以查出画板board的所有pin,然后查出pin所对应的Imagekey(图片存储在第三方的一个ID),第三方固定地址:"http://img.hb.aicdn.com/%s_fw658" %Imagekey"。

代码逻辑:

1. 传递“画板ID"参数,可以直接用sys.argv位置参数,我用了内置模块argparse解析选项参数。

if __name__ == "__main__":
    import argparse
    parser = argparse.ArgumentParser()
    parser.add_argument("-b", "--board", help="The board id for Huanban.com", type=int)
    args = parser.parse_args()
    if args.board:
        print GetBoard(args.board)

2. 获取画板参数后,执行GetBoard函数(传递board)。

def GetBoard(board):
    代码

以下代码获取画板所有图片数量,title number:

    #get title pin number
    r = requests.get(url, timeout=15, verify=False, headers=headers)
    title_pat = re.compile(r'<title>.*\((\d+).*\).*</title>')
    data=r.text.encode('utf-8')
    allimages = re.findall(title_pat, data)[0]

以下代码获取首屏图片pins:

    #first
    url  = "http://huaban.com/boards/%s/?limit=%d" %(board, int(limit))
    data = requests.get(url, timeout=10, verify=False, headers=headers).text.encode('utf-8')
    pins = [ _[-1] for _ in re.findall(pat, data) if _[-1] ]

以下代码不断循环刷新请求,直到获取不到任何pin,则中断:

    while not END:
        #ajax
        url  = "http://huaban.com/boards/%s/?max=%s&limit=%s&wfl=1" %(board, pins[-1], limit)
        data = requests.get(url, timeout=10, verify=False, headers=headers).text.encode('utf-8')
        _pins= [ _[-1] for _ in re.findall(pat, data) if _[-1] ]
        print "ajax get %s pins, last pin is %s, merged" %(len(_pins), pins[-1])
        _pins= [ _[-1] for _ in re.findall(pat, data) if _[-1] ]
        pins += _pins
        if len(_pins) == 0:
            break

以上步骤获取到所有pin,结果是list,循环此list,下载每个pin图片保存,这里后续改为multiprocessing.dummy多线程并发,当前顺序执行很慢(哎、Python)。

看看效果:



################################################################

代码库:https://github.com/staugur/grab_huaban_board/releases/tag/v2.0

版本更新至2.0,变化为:

1. 获取所有pins,使用multiprocessing.dummy的线程池,线程并发数量可以用-p(--processes)指定,速度大幅度增加;

2. 记录日志

################################################################

代码库:https://github.com/staugur/grab_huaban_board/releases/tag/v3.0

版本更新至3.0,新功能:

1. 整体代码调整

2. 多画板抓取,每个画板一个进程,每个进程用线程池

QQ截图20170103212512


################################################################

代码库:https://github.com/staugur/grab_huaban_board/releases/tag/v4.0

版本更新至4.0,新功能:

1. 抓取用户下指定数量(limit)的画板,每个用户开启一个进程,每个用户下每个画板开启子进程,所以limit设置的值切记不要过大,默认10,如果用户有10个以上画板,将只下载10个,开启10个进程,建议不要超过50(根据机器硬件情况)。

修改此值,需编辑grab_huaban_board.py,GetUserBoards函数,修改limit默认函数值。

2.多用户抓取