zoukankan      html  css  js  c++  java
  • python爬虫–爬取煎蛋网妹子图片

    前几天刚学了python网络编程,书里没什么实践项目,只好到网上找点东西做。
    一直对爬虫很好奇,所以不妨从爬虫先入手吧。

    Python版本:3.6

    这是我看的教程:Python - Jack -Cui -CSDN

    大概学了一下urllib,beautifulsoup这两个库,也看了一些官方文档,学会了这两个库的大概的用法。

    urllib用来爬取url的内容,如html文档等。beautifulsoup是用来解析html文档,就像js的DOM操作一样。简单流程如下:

    from urllib import request
    from bs4 import BeautifulSoup
    #urllib操作
    url = 'http://blog.csdn.net/'
    #编辑header,至少要把User-Agent写上,否则python会自动加上,导致直接被有反爬虫机制的网站识别
    #有很多网站会有个Content-Encoding=gzip,进行后面的输出时一定要gzip解压缩,具体怎么解压缩,看看这个:https://www.jianshu.com/p/2c2781462902
    headers = {
        'Connection' : 'keep-alive',
        'Cache-Control' : 'max-age=0',
        'User-Agent' : 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.89 Safari/537.36'
    }
    req = request.Request(url, headers=headers)
    response = request.urlopen(req)
    html = response.read()
    #输出html内容
    print(html)
    #beautifulsoup操作
    soup = BeautifulSoup(html, 'lxml')
    #选取所有a标签
    a_tags = soup.find_all('a')
    #获得a标签中的内容(string属性)
    for item in a_tags:
        print(item.string)
    

    基础内容差不多就这些,下面来爬一下煎蛋。
    先看一下其源代码,发现源html中并没有图片的链接,而是只有一个没有url的img标签和一个有img-hash属性的span标签

    查看js文件,寻找jandan_load_img()函数

    分析可知,由span的img-hash属性的值和一个固定的hash作为参数,传入一个f_开头的函数,将返回值直接插入html文档中的a的href中,可见,返回值就是图片的真实url。所以思路有了:用python模拟js的函数,先取img-hash的值,再传入一个解密函数(对应f_开头函数),得到图片url。再看一下jandan_load_img()函数,取回url之后,如果文件后缀名为.gif,则在其中加入'thumb180'字符串,这个好做。
    下面直接贴个源码吧:

    #!/usr/bin/env python3
    from bs4 import BeautifulSoup
    from urllib import request
    import argparse
    import hashlib
    import base64
    import gzip
    import time
    import os
    import io
    import re
    
    headers = {
        'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.89 Safari/537.36',
        'Accept-Encoding':'gzip, deflate',
        'Accept-Language':'zh-CN,zh;q=0.9',
        }
    
    def md5(src):
        m = hashlib.md5()
        m.update(src.encode('utf-8'))
        return m.hexdigest()
    
    def decode_base64(data):
        missing_padding=4-len(data)%4
        if missing_padding:
            data += '='* missing_padding
        return base64.b64decode(data)
    
    def calculate_url(img_hash, constant):
        k = 'DECODE'
        q = 4
        constant = md5(constant)
        o = md5(constant[0:16])
        #n = md5(constant[16:16])
        n = md5(constant[16:32])
        
        l = img_hash[0:q]
        c = o+md5(o + l)
    
        img_hash = img_hash[q:]
        k = decode_base64(img_hash)
        h = []
        for g in range(256):
            h.append(g)
    
        b = []
        for g in range(256):
            b.append(ord(c[g % len(c)]))
    
        f = 0
        for g in range(256):
            f = (f + h[g] + b[g]) % 256
            tmp = h[g]
            h[g] = h[f]
            h[f] = tmp
    
        t = ""
        f = 0
        p = 0
        for g in range(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_raw_html(url):
        req = request.Request(url=url, headers=headers)
        response = request.urlopen(req)
        text = response.read()
        encoding = response.getheader('Content-Encoding')
        if encoding == 'gzip':
            buf = io.BytesIO(text)
            translated_raw = gzip.GzipFile(fileobj=buf)
            text = translated_raw.read()
    
        text = text.decode('utf-8')
        return text
    
    def get_soup(html):
        soup = BeautifulSoup(html, 'lxml')
        return soup
    
    def get_preurl(soup):
        preurl = 'http:'+soup.find(class_='previous-comment-page').get('href')
        return preurl
    
    def get_hashesAndConstant(soup, html):
        hashes = []
        for each in soup.find_all(class_='img-hash'):
            hashes.append(each.string)
    
        js = re.search(r'<scriptssrc="//(cdn.jandan.net/static/min/.*?)">.*?</script>', html)
        jsFileURL = 'http://'+js.group(1)
        jsFile = get_raw_html(jsFileURL)
    
        target_func = re.search(r'f_w*?(e,"(w*?)")', jsFile)
        constant_hash = target_func.group(1)
    
        return hashes, constant_hash
    
    def download_images(urls):
        if not os.path.exists('downloads'):
            os.makedirs('downloads')
        for url in urls:
            filename = ''
            file_suffix = re.match(r'.*(.w+)', url).group(1)
            filename = md5(str(time.time()))+file_suffix
            request.urlretrieve(url, 'downloads/'+filename)
            time.sleep(3)
    
    def spider(url, page):
        #get hashes, constant-hash, previous page's url
        html = get_raw_html(url)
        soup = get_soup(html)
    
        params = get_hashesAndConstant(soup, html)
        hashes = params[0]
        constant_hash = params[1]
    
        preurl = get_preurl(soup)
        
        urls = []
        index = 1
        for each in hashes:
            real_url = 'http:'+calculate_url(each, constant_hash)
            replace = re.match(r'(//w+.sinaimg.cn/)(w+)(/.+.gif)', real_url)
            if replace:
                real_url = replace.group(1)+'thumb180'+replace.group(3)
            urls.append(real_url)
            index += 1
    
        download_images(urls)
    
        page -= 1
        if page > 0:
            spider(preurl, page)
    
    
    if __name__ == '__main__':
        #user interface
        parser = argparse.ArgumentParser(description='download images from Jandan.net')
        parser.add_argument('-p', metavar='PAGE', default=1, type=int, help='the number of pages you want to download (default 1)')
        args = parser.parse_args()
        
        #start crawling
        url = 'http://jandan.net/ooxx/'
        spider(url, args.p)
    
    

    防止被识别,采取了以下措施:

    运行的时候可以加个-p参数,是要下载的页数,默认是1。
    每爬一张图片暂停3s,为了防止被服务器识别,你们嫌慢的话可以改短一点。
    

    下载的图片保存在当前目录的downloads文件夹下(没有则创建)。
    ps:用Windows的同学请注意!这里说的当前目录不是指这个python文件的路径,而是cmd中的当前路径!我一开始是在Linux上做的,后来在Windows测试的时候一直找不到downloads文件夹,把源代码检查了好久,最后才发现是路径问题。。

    pps:此项目也可以在我的Github中找到(更有.exe文件等你来发现~滑稽)。

    参考:

    http://blog.csdn.net/c406495762/article/details/71158264

    http://blog.csdn.net/van_brilliant/article/details/78723878

  • 相关阅读:
    【PyQt5-Qt Designer】对话框系列
    【PyQt5-Qt Designer】界面布局
    【PyQt5-Qt Designer】PyQt5+eric6 安装和配置
    【PyQt5-Qt Designer】QMessageBox 弹出框总结
    【PyQt5-Qt Designer】鼠标+键盘事件
    【PyQt5-Qt Designer】猜数字(小项目)
    【PyQt5-Qt Designer】浅谈关闭窗口
    【PyQt5-Qt Designer】窗口操作
    【python基础】利用pandas处理Excel数据
    【python基础】os.path模块常用方法详解
  • 原文地址:https://www.cnblogs.com/litlife/p/8087355.html
Copyright © 2011-2022 走看看