python爬虫实战2:动态爬图片


[success]前面说了爬取小说,这里爬小说爬的是静态的内容,我们现在要爬的是动态内容:也就是说我们不能直接从页面获取数据。这里我演示的是一个图片网站,它里面的图片是通过json数据来获取的,废话不多说,直接开始演示。[/success]

这里因为获取的是json数据,所以我们需要用到一个抓包工具:fiddler(下载链接下面会贴出来)。这个软件刚开始配置起来还是挺麻烦的,这里我直接说一下关于https的配置问题。首先要把证书都清掉。(把带有DO_NOT的都删掉,没有就不管)

然后需要到软件的配置界面(在工具的选项里)

点击这个,然后就会重新配置自己的证书,如果还是有问题,可以多试几次,在有问题自己百度解决。

配置好后我们就可以打开它然后自己再到浏览器里面打开那个网站,下载一个图片,然后回到软件,可以看到抓到了很多数据,我们这里只需要找json类型的就可以了,大家慢慢找,如果找到了下图的json数据就说明找到数据了。

里面的内容是这样的:

然后我们可以发现json里面带有图片的下载链接,所以我们可以直接获取json数据并且下载图片了。

但是,这里还有一个问题:就是这个网站采用了反爬虫机制,直接这样访问是没有数据的,我们可以先看一下请求头发现里面有很多数据,这里面就有一些认证信息,我们可以把这些认证信息也发过去,这样就可以合法获取json数据了。这里我发现只需要发送ugid就是行了:(比如我的:ugid=dc2b8cce996a342b4b1cdaf4ff996d6b5192814)。

那么现在就直接贴代码了(代码里面都有注释):

# -*- coding:UTF-8 -*-
import requests,json #引用相应的库
from contextlib import closing#这个是图片下载的库
target='https://unsplash.com/napi/photos?page=5&per_page=12'#这个是请求的地址,大家可以根据自己获得的json的那个请求标头自己修改
headers = {'ugid':'dc2b8cce996a342b4b1cdaf4ff996d6b5192814'}#这个是我们浏览时的认证id,我们可以让爬虫发送这个获取合法身份
req=requests.get(url=target, headers=headers)#这里就是发送请求,然后获得结果
html=json.loads(req.text)#这里就是把我们获取到的数据转换成json格式,这样后面就更好处理
for each in range(len(html)):#这里就是遍历json数据(因为json里面有多个图片的地址)
    target=html[each]['links']['download']#这里是获取图片的链接(我们可以把json看成字典,可以直接访问里面的内容)
    print("正在下载:%s 当前连接%s:" %(html[each]['id'],target))#这里获取图片的id然后显示出来
    with closing(requests.get(url=target, stream=True, headers = headers)) as r:#这里就是下载图片的代码了
        with open('%s.jpg' %html[each]['id'] , 'ab+') as f:#这里是保存图片
            for chunk in r.iter_content(chunk_size = 1024):#下面都是下载图片数据的代码,所以不解释
                if chunk:
                    f.write(chunk)
                    f.flush()

你以为这就没了?不我们现在换一个来玩,我直接选择了百度图库作为实验对象,发现百度图库也是json数据,而且这个没有身份认证,既然如此,那么我们来干波大的:一次性下载500张图片!既然要下载这么多那么我们就应该使用到Python的多线程,说干就干。详细原理我也不多讲了,很多东西都会在代码里面说明,直接上代码:

# -*- coding:UTF-8 -*-
import requests,json,os
from urllib import parse
from urllib.request import urlretrieve
from threading import Thread
class img(object):
    def __init__(self):
        self.target="https://image.baidu.com/search/acjson?tn=resultjson_com&ipn=rj&ct=201326592&is=&fp=result&queryWord=replaceword1&cl=2&lm=-1&ie=utf-8&oe=utf-8&adpicid=&st=-1&z=&ic=0&hd=&latest=©right=&word=replaceword2&s=&se=&tab=&width=&height=&face=0&istype=2&qc=&nc=1&fr=&expermode=&force=&pn=replaceword3&rn=30&gsm=3c&1557964527823="
        self.keyword=''#关键字
        self.num=''#要爬取的数量
        self.names=[]#图片名字
        self.urls=[]#图片链接
    #获取图像url
    def geturl(self):
        for each in range(30,self.num+30,30):#因为我们设置百度时一次性获取30张的,所以我们直接加上30,多爬一点链接
            #这里是替换关键词,因为我们是自定义下载关键词的,所以在这里一次性替换掉
            target = self.target.replace('replaceword1',self.keyword).replace('replaceword2', self.keyword).replace('replaceword3',str(each))
            #这里就是获取json数据
            req = requests.get(url=target)
            html = json.loads(req.text)#把内容换成json
            html=html['data']#获取主体内容
            for i in range(len(html)-1):
                self.names.append(html[i]['di']+'.'+html[i]['type'])#这里就是不断的把名字和链接加到我们的列表里
                self.urls.append(html[i]['thumbURL'])
    #下载图像
    def download(self,url,name):#这里就是下载图像的函数,配合多线程使用,使下载速度加倍
        print ('正在下载:%s' %name)
        if not os.path.exists('img'):#这里是创建文件夹
            os.makedirs('img')
        name='img/'+name#这里就是换一个路径,下载到img下
        urlretrieve(url,name)#下载图像
    # 多线程下载图像
    def moredown(self):
        threads = []#这里我们使用多线程,要把这些线程放到列表里
        for i in range(self.num):#我们要下多少图片就开多少线程
            t =Thread(target=self.download(self.urls[i], self.names[i]))#把函数加到线程里面
            t.start()#开始线程
            threads.append(t)#把线程都加到列表里面,方便后面判断是否下载完毕
        for t in threads:
            t.join()#这里就是等待线程结束的代码
        print ("下载完成")

    #开始下载
    def start(self):
        s = input("请输入关键词:")
        if s=='':
            print ('你还没有输入关键词!')
            return
        im.keyword = parse.quote(s)
        n = input("请输入需要下载的数量:")
        if (not n.isdigit()) or n=='':
            print ('你输入的不是数字!')
            return
        im.num = int(n)
        self.geturl()
        self.moredown()
if __name__=="__main__":
    im = img()
    while True:
        im.start()

实际效果演示:

这个可能是因为爬的速度太快或者爬的太多了吧,那边直接断开了连接,不过我们还是爬了372张图片,平均每秒2张的下载速度。所以说实验还是挺成功的。

突然发现我下载的好像都是略缩图。。。,不过这个细节不用在意具体可以自己修改一下代码逻辑,我这里也懒得搞了。

fidder下载地址:[bdbtn]https://pan.xiaoyou66.com/s/8oao3dzf[/bdbtn]


文章作者: 小游
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 小游 !
  目录