美文网首页python自学
如何使用Python批量爬取网页的图片资源

如何使用Python批量爬取网页的图片资源

作者: 老夫撸代码 | 来源:发表于2019-02-23 20:43 被阅读6次

    欢迎关注微信公众号:老夫撸代码
    微信小程序写多了,老夫也换换口味,写点儿其它的教程
    10分钟教程:如何使用Python批量爬取网页的图片资源
    敲黑板,知识点:
    正则表达式、网络请求、读写文件、SSL认证、操作文件夹、Base64解析图片

    为什么出这个教程?

    最近公司业务需要开发一些基于微信小程序的营销类工具,比如:砸金蛋、大转盘、九宫格抽奖等等,所以老夫参考了一些网赚平台的H5营销工具,使用Taro来开发小程序端的营销工具。
    老夫先将此网址贴出来,链接如下:
    https://activity.tuiayonghu.com/activity/index?id=9150&slotId=193506&login=normal&appKey=uuNX4GQ6Xoi9mNG2yZcz3eYBRf1&deviceId=212a63c1-0fb1-4f9b-8fcf-70bfb1a6df94&dsm=1.193506.0.0&tenter=SOW&subActivityWay=2&tck_rid_6c8=0ad021cejrhq8cb9-6019810&tck_loc_c5d=tactivity-9150&dcm=401.193506.0.0&&tenter=SOW
    手机浏览器效果如下图:

    WechatIMG100.jpeg

    老夫只是想借用一下对方的图片资源,一般获取一个网页的图片资源有以下几种方式:

    1. 在当前页面右键-另存为,就会将当前页面的样式文件、图片资源、字体资源等下载到本地
    2. 通过F12,打开开发者工具 - Sources - 右键 - Open in new tab ,在新页面中另存为即可

    上述1方法一般是大家用的方式,但是仅限于当前页面请求过的图片资源,如果是通过js加载的资源是获取不到的。

    上述2方法不推荐,费时间。

    上面讲到的两种方法都不适用,因为这个链接只支持手机打开,在pc上面打开会跳页的,所以我们通过python来获取网页的图片资源。

    没有什么事情是通过写程序办不到,如果办不到,请多写几个程序!
    以下涉及到的代码使用的是python3的语法

    人生苦短,我用Python

    这里我用大概138行的python来实现爬取图片资源并保存到本地的过程。
    为什么不用其它语言来实现而用 python 来实现?
    因为python入门低,而且各种类库用的那个爽。

    第一步:通过url获取目标文件源码

    我们通过python自带的标准库 urllib.request 来构造请求,并获取请求到的内容,并把这些内容写入到index.html文件中,示例代码如下:

    '''
    author:老夫撸代码
    wechat:cxyzxh1388
    获取目前url的源文件
    '''
    def getIndex():
    
        #目标url
        url = "https://activity.tuiayonghu.com/activity/index?id=9150&slotId=193506&login=normal&appKey=uuNX4GQ6Xoi9mNG2yZcz3eYBRf1&deviceId=212a63c1-0fb1-4f9b-8fcf-70bfb1a6df94&dsm=1.193506.0.0&tenter=SOW&subActivityWay=2&tck_rid_6c8=0ad021cejrhq8cb9-6019810&tck_loc_c5d=tactivity-9150&dcm=401.193506.0.0&&tenter=SOW"
    
        request = urllib.request.Request(url)
    
        #去掉ssl认证
    
        ssl._create_default_https_context = ssl._create_unverified_context
    
        with urllib.request.urlopen(request) as f:
    
            html = f.read()
            '''因为html读出来的是二进制,因此写入index.html也必须以二进制的形式'''
            with open('index.html','wb') as fb:
                fb.write(html)
    
        currpath = os.getcwd()
    
        if not os.path.exists(currpath+'/css'):
            os.mkdir(currpath + '/css')
        if not os.path.exists(currpath+'/images'):
            os.mkdir(currpath + '/images')
    
        return os.getcwd()+'/index.html'
    

    代码解析:

    1. urllib读取url的时候,返回的是二进制格式的内容,因此保存到文件种也必须是以wb的方式写入
    2. 在保存index.html的同时,新建css文件夹和images文件夹

    有一点儿需要注意的是:
    如果url是以https开头的,我们需要将ssl认证关闭,代码如下:

    import ssl
    ssl._create_default_https_context = ssl._create_unverified_context
    

    第二步:处理index.html源码中的图片资源

    通过分析生成的index.html的文件结构,我们发现并没有任何一个显式声明的img标签存在于html的标签当中,更多的是将图片资源的链接拼接到js代码中:

    "value":"//yun.tuitiger.com/mami-media/img/1vxv3dun0w.png"
    "image":"//yun.tuiayonghu.com/mami-media/img/el1bddtppl.png"
    

    先上代码:

    '''
    获取直接页面的图片资源
    '''
    def getIndexImage(path):
        soup = BeautifulSoup(open(path), 'lxml')
        '''获取页面中img标签'''
        imgs = soup.find_all('img')
        if len(imgs) > 0:
            #todo 保存Url图片,因为此链接的源码页面中并没有img标签,所以这里不做处理
            print()
        '''获取js变量中的img路径'''
        with open(path) as p:
            content = p.read()
            imglist = re.findall('("image":[^,]*,)',content)
            print(imglist)
            for img in imglist:
                arr = img.split(':')
                url = 'http:'+arr[1][1:-2]
                saveImage(url)
            valuelist =re.findall('("value":"//yun[^,]*,)',content)
            print(valuelist)
            for img in valuelist:
                arr = img.split(':')
                url = 'http:'+arr[1][1:-2]
                saveImage(url)
    
    '''将url图片路径保存为图片'''
    def saveImage(url):
        name = url[url.rindex('/')+1:]
        with urllib.request.urlopen(url) as i:
            content = i.read()
            with open(os.getcwd()+'/images/'+name,'wb') as f:
                f.write(content)
                print('保存图片:'+name+'\n')
    

    代码解析:

    1. 上述代码主要用到一个类库 BeautifulSoup,它是一个可以从HTMLXML文件中提取数据的Python库.它能够通过你喜欢的转换器实现惯用的文档导航,查找,修改文档的方式.Beautiful Soup会帮你节省数小时甚至数天的工作时间.
    2. imgs = soup.find_all('img') 此方法就是在当前文档结构中查找所有显式声明的img标签
    3. 上述代码 12 ~ 25 行代码是通过正则表达式将所有拼接到js中的图片路径找到,并且保存到images的文件夹中。

    第三步:保存index.html中的css文件

    在前两步,我们已经将index.html中涉及到的图片资源都已保存下来,但是那些通过js加载的图片,还未处理。
    我们先处理隐藏到css中的图片资源。
    css中的图片资源分为两种:

    1. 图片资源链接
    2. base64格式的图片资源

    上述 1 中的图片资源很好处理,我们通过正则表达式先将这些图片链接筛选处理,然后再通过模拟请求,保存到本地,代码如下:

    #保存css文件
    def dealCss(path):
        soup = BeautifulSoup(open(path), 'lxml')
        links = soup.find_all('link', attrs={'href': re.compile('.css')})
        '''
         保存css文件到文件夹中
        '''
        list = []
        for link in links:
            href = 'http:' + link['href']
            name = href[href.rindex('/') + 1:]
            request = urllib.request.Request(href)
            with urllib.request.urlopen(request) as u:
                css = u.read()
                with open(os.getcwd()+'/css/'+name,'wb') as f:
                    f.write(css)
        '''
        通过正则表达式提取base64数据和图片路径
        '''
        dirss = os.listdir(os.getcwd()+'/css')
        for dir in dirss:
            with open(os.getcwd()+'/css/'+dir) as f:
                content = f.read()
                reglist = re.findall('(url\([^\)]*\);)',content)
                for i in reglist:
                    real = i[i.index('(')+1:i.rindex(')')]
                    if real.startswith("//"):
                        saveImage('http:'+real)
                    else:
                        saveBase64(real)
    

    代码解析:

    1. 3~16行代码是获取index.html中显式声明的css文件,并保存。
    2. 20~28行代码是通过对已保存的css文件,进行正则表达式找到图片的路径。因为在css中只能通过background-image:url(*****)来加载图片,url中即可以加载图片又可以加载base64编码的图片数据,所以我们需要分开处理。
    3. '(url([^)]);)'* 这个正则表达式获取了所有加载的图片
    4. i[i.index('(')+1:i.rindex(')')] 是获取了url里面包括的数据
    5. real.startswith("//") 判断是否为图片链接

    第四步:解码base64格式的图片并保存

    cssbase64图片的格式为如下:
    background-image: url("data:image/png;base64,iVBORw0KGgo=...");
    其中iVBORw0KGgo=...才是base64编码的数据,我们需要把这部分数据解码,然后保持到图片文件中。

    '''将base64的编码转换为图片格式'''
    def saveBase64(code):
        rc = re.search('data:image\/[a-z]+;',code).group()
        ext = '.'+rc[rc.rindex('/')+1:-1]
        name = ''.join(random.sample(['z','y','x','w','v','u','t','s','r','q','p','o','n','m','l','k','j','i','h','g','f','e','d','c','b','a'], 8))
        seq = re.search('data:image\/[a-z]+\;base64,',code).span()
        print(seq)
        newcode = code.replace(code,code[seq[1]:-1])
        print(newcode+'\n')
        with open(os.getcwd()+'/images/'+name+ext,'wb') as f:
            if len(newcode) % 4 != 0:  # check if multiple of 4
                while len(newcode) % 4 != 0:
                    newcode = newcode + "="
                req_str = base64.b64decode(newcode)
            else:
                req_str = base64.b64decode(newcode)
            f.write(req_str)
    

    代码解析:

    1. data:image/png表示当前的图片格式是png
    2. 4~5 行代码表示获取图片的扩展名和生成随机图片名称
    3. 6~8 行代码获取base64的数据格式
    4. 10~17 行代码将base64的数据格式解码并且保存到图片文件中。
      ......

    关注微信公众号:老夫撸代码 回复数字 1009 获取完整代码

    老夫撸代码

    相关文章

      网友评论

        本文标题:如何使用Python批量爬取网页的图片资源

        本文链接:https://www.haomeiwen.com/subject/rwqmyqtx.html