首先讲下爬取网站图片是动态加载的(参考文章:动态爬取百度图),以百度图片为例,打开百度图片,我搜索的关键字是“猫”:

http://image.baidu.com/search/index?tn=baiduimage&ps=1&ct=201326592&lm=-1&cl=2&nc=1&ie=utf-8&word=猫

在看到搜索出的图片的网页按F12,出现下图;

python 爬取图片 训练cnn_python 爬取图片 训练cnn

切换右侧标签到Network,然后网页往下拉,这时浏览器地址栏网址未变,而网页中图片却一张张增加(这就是所说的动态加载),说明网页在后台与服务器交互数据。

有列写着XHR,这个的英文全名为XmlHttpRequest,即可扩展超文本传输请求。Xml可扩展标记语言,Http超文本传输协议,Request请求。XMLHttpRequest对象可以在不向服务器提交整个页面的情况下,实现局部更新网页。当页面全部加载完毕后,客户端通过该对象向服务器请求数据,服务器端接受数据并处理后,向客户端反馈数据。  点开Network标签中 XHR列中的某一条,在右侧Hearders的Request URL发现末尾的“pn=…………=”这些内容,对比其他XHR链接的Request URL,可以发现,基本上是一样的,除了末尾“pn=…………=”一点点差异。

只是pn的值不一样,测试发现,pn应该是表示当前请求的图片序号,rn表示更新显示图片的数量。 pn=90&rn=30&gsm=5a&1484307466221= 

pn=120&rn=30&gsm=5a&1484307466223= 
pn=150&rn=30&gsm=78&1484307469213= 
pn=180&rn=30&gsm=78&1484307469214= 
pn=210&rn=30&gsm=b4&1484307553244=

推荐一款Chrom的插件,Json handle。很方便。  百度云下载地址。链接:http://pan.baidu.com/s/1qXZEjaW 密码:nxr5

现在知道了,其实我们只要不断访问这个Request URL,改变他的pn值理论上就可以实现下载多张图片了。

python 爬取图片 训练cnn_百度_02

 

如果想看关键字的编码可用以下语句:

>>>import urllib
>>>keyword="猫"
>>>keyword=urllib.quote(keyword)
>>>keyword

获取当前页所有图片的链接

右键点击查看网页html源文件,发现同一张图片共有4种链接(如下图):

python 爬取图片 训练cnn_python_03

主要区别是分辨率不同,objURL是图片的源也是最清楚的一张。经测试,其他三个都要反爬虫措施,用浏览器可以打开,但是刷新一次就403 Forbidden。用爬虫获取不到图片。

第四种objURL是指图片的源网址,获取该网址会出现三种情况:

1.正常。可继续下载;

2.403 Forbidden。用continue跳过;

3.出现异常。用try excep处理;

 

图片的网址都是这样的格式: "objURL":"网址", 那就好办了, 直接用正则表达式就能解决

import re
pattern_pic = '"objURL":"(.*?)",'
# 这里的html就是网页的源代码的内容, 此处不介绍, 稍后给出
pic_list = re.findall(pattern_pic, html, re.S)  # 存储当前页的所有关键字的图片的url的列表

其中正则表达式的解释和例子推荐看这篇文章:import re

获取当前页的下一页的链接

用正则得出:

pattern_fanye = '<a href="(.*)" class="n">下一页</a>'
fanye_url = re.findall(pattern_fanye, html)[0]  # 下一页的链接

获取所有页的图片链接

图片的网址都是这样的格式: "objURL":"网址",  直接用正则表达式就能解决:

import re 
pattern_pic = '"objURL":"(.*?)",' 
# 这里的html就是网页的源代码的内容,
pic_list = re.findall(pattern_pic, html, re.S)  # 存储当前页的所有关键词的图片的url的列表

获取所有页的图片的链接

上面已经根据当前页的url得到了当前页的所有图片的链接, 以及下一页的url.  如此, 循环下去, 即可得到每一页的所有图片的链接.

all_pic_list = []  # 存储所有翻页的所有图片的链接的列表 
while 1:     
    all_pic_list.extend(pic_list)     
    if 循环完所有翻页:        
        break

下载图片

知道图片链接了,直接下载:

for i, pic_url in enumerate(all_pic_list):
    pic = requests.get(pic_url)
    string = str(i + 1) + '.jpg'
    with open(string, 'wb') as f:
        f.write(pic.content)

完整源代码如下:(也可参考这篇爬泰勒斯威夫的图片,源码和以下类似:爬取百度图片(泰勒))

# coding=utf-8
"""根据搜索词下载百度图片"""
import re
import sys
import urllib

import requests


def get_onepage_urls(onepageurl):
    """获取单个翻页的所有图片的urls+当前翻页的下一翻页的url"""
    if not onepageurl:
        print('已到最后一页, 结束')
        return [], ''
    try:
        html = requests.get(onepageurl).text
    except Exception as e:
        print(e)
        pic_urls = []
        fanye_url = ''
        return pic_urls, fanye_url
    pic_urls = re.findall('"objURL":"(.*?)",', html, re.S)
    fanye_urls = re.findall(re.compile(r'<a href="(.*)" class="n">下一页</a>'), html, flags=0)
    fanye_url = 'http://image.baidu.com' + fanye_urls[0] if fanye_urls else ''
    return pic_urls, fanye_url


def down_pic(pic_urls):
    """给出图片链接列表, 下载所有图片"""
    for i, pic_url in enumerate(pic_urls):
        try:
            pic = requests.get(pic_url, timeout=15)
            string = str(i + 1) + '.jpg'
            with open(string, 'wb') as f:
                f.write(pic.content)
                print('成功下载第%s张图片: %s' % (str(i + 1), str(pic_url)))
        except Exception as e:
            print('下载第%s张图片时失败: %s' % (str(i + 1), str(pic_url)))
            print(e)
            continue


if __name__ == '__main__':
    keyword = '猫'  # 关键词, 改为你想输入的词即可, 相当于在百度图片里搜索一样
    url_init_first = r'http://image.baidu.com/search/flip?tn=baiduimage&ipn=r&ct=201326592&cl=2&lm=-1&st=-1&fm=result&fr=&sf=1&fmq=1497491098685_R&pv=&ic=0&nc=1&z=&se=1&showtab=0&fb=0&width=&height=&face=0&istype=2&ie=utf-8&ctd=1497491098685%5E00_1519X735&word='
    url_init = url_init_first + urllib.quote(keyword, safe='/')
    all_pic_urls = []
    onepage_urls, fanye_url = get_onepage_urls(url_init)
    all_pic_urls.extend(onepage_urls)

    fanye_count = 0  # 累计翻页数
    while 1:
        onepage_urls, fanye_url = get_onepage_urls(fanye_url)
        fanye_count += 1
        print('第%s页' % fanye_count)
        if fanye_url == '' and onepage_urls == []:
            break
        all_pic_urls.extend(onepage_urls)

    down_pic(list(set(all_pic_urls)))

 

用正则方式爬取其他非百度图片网站的图,可参考:爬取游戏网页图片

代码:  

其实很简单,我们直接看下整体的代码:  

#coding = utf-8
import urllib
import re

def getHtml(url):
    page = urllib.urlopen(url)
    html = page.read()
    return html

def getImg(html):
    reg = 'src="(.+?\.jpg)" alt='
    imgre = re.compile(reg)
    imglist = re.findall(imgre, html)
    x = 0
    for imgurl in imglist:
        urllib.urlretrieve(imgurl, '%s.jpg' % x)
        x+=1
    return imglist

html = getHtml("http://pic.yxdown.com/list/0_0_1.html")

print getImg(html)

 

导入库:  

第一行的utf-8是为了支持中文。  这里我们导入了两个库,分别是 urllib 和 re。urllib 是用来进行 url 网络请求的,而 re 是一个正则表达式匹配的库。这里我们要先对网站进行模拟请求,然后找到网站中的图片进行下载。  

请求网站: 

第一个方法:getHtml。  这就是用来模拟浏览器访问网站的,参数 url 是要访问的网站链接,这里我们在下面的变量 html 处调用了这个方法,其访问的 url 是一个图片网站,关于选择访问网站还有一点等下要说一下。  在这个方法中,我们先用了 urllib 库的 urlopen 方法来打开网站,然后通过 read 方法来获取网站的源代码,其实就跟在网页中“右键–>检查“是一个意思。最后返回了读取到的网站源代码。  上面说了要注意的一点是,由于很多网站会禁止人们随意爬取数据,有反爬虫的技术,所以在选择要爬取的网站的时候,最好先通过这个方法获取网站源代码,然后 print 输出 html 变量看一下获取到的内容是否是正常的网页源代码,而不是403之类的禁止访问,如果被禁止了,那么自然也不可能爬取到数据了。  

找到图片:  

接下来是一个 getImg 方法。  在这个方法中,我们设置了一个正则表达式,用来在网页源代码中找到图片的资源路径,这个正则表达式要根据不同的网站去具体设置,比如我爬取的这个网站,图片对应的源代码是这样的:  

python 爬取图片 训练cnn_百度_04

 因此我们设置的正则表达式就是 reg = ‘src=”(.+?.jpg)” alt=’ ,其实就是根据图片资源路径前后的内容来限制的。  这里也要注意一点,有的网站做了动静分离,图片有其单独的完整资源路径,而有的是直接是相对位置,这时候要么对其路径进行处理,但大多时候你并不知道怎么处理才能拼出完整路径,因此还是找有完整资源路径的图片来试验比较好。  紧接着用 re 库的 compile 函数将正则表达式转换成正则表达式对象,然后使用 findall 函数寻找 html 网页源代码中包含的匹配 imgre 的所有内容,返回一个序列。我们可以输出这个序列,可以看到大量图片资源路径组成的一个序列,如果没爬取到,就是个空序列了。  下载图片  最后一步就是下载图片,这里我们用 for 循环,将图片资源路径中的每个图片,使用 urllib 库的 urlretrieve 函数来下载图片,这个函数其实可以接受很多参数,这里我们设置了要下载的图片资源路径和要命名的名字(我们使用一个变量x来对每个图片依次命名为0,1,2…),还可以设置下载路径、用来显示下载进度的回调函数等等。如果不设置下载路径默认会下载到代码文件当前所在的文件夹。  

执行 

现在,去执行一次代码就可以,直接将代码放入一个 .py 文件中,使用终端进入其文件位置,敲入 python xxx.py 命令就可以。

 

用多线程对图片进行爬取:多线程爬取百度图,多线程动态爬取百度图

 

通过关键字爬取多张百度图片

这个爬取妹子的链接……作者还真是人才,写的蛮好的,故推荐:爬取妹子图片

这个爬取百度图片,鉴定可行:爬取百度图片



# -*- coding: utf-8 -*-
import re
import requests
from urllib import error
from bs4 import BeautifulSoup
import os
num = 0
numPicture = 0
file = ''
List = []

def Find(url, A):
    global List
    print('正在检测图片总数,请稍等.....')
    t = 0
    i = 1
    s = 0
    while t < 1000:
        Url = url + str(t)
        try:
            # 这里搞了下
            Result = A.get(Url, timeout=7, allow_redirects=False)
        except BaseException:
            t = t + 60
            continue
        else:
            result = Result.text
            pic_url = re.findall('"objURL":"(.*?)",', result, re.S)  # 先利用正则表达式找到图片url
            s += len(pic_url)
            if len(pic_url) == 0:
                break
            else:
                List.append(pic_url)
                t = t + 60
    return s

def recommend(url):
    Re = []
    try:
        html = requests.get(url, allow_redirects=False)
    except error.HTTPError as e:
        return
    else:
        html.encoding = 'utf-8'
        bsObj = BeautifulSoup(html.text, 'html.parser')
        div = bsObj.find('div', id='topRS')
        if div is not None:
            listA = div.findAll('a')
            for i in listA:
                if i is not None:
                    Re.append(i.get_text())
        return Re


def dowmloadPicture(html, keyword):
    global num
    # t =0
    pic_url = re.findall('"objURL":"(.*?)",', html, re.S)  # 先利用正则表达式找到图片url
    print('找到关键词:' + keyword + '的图片,即将开始下载图片...')
    for each in pic_url:
        print('正在下载第' + str(num + 1) + '张图片,图片地址:' + str(each))
        try:
            if each is not None:
                pic = requests.get(each, timeout=7)
            else:
                continue
        except BaseException:
            print('错误,当前图片无法下载')
            continue
        else:
            string = file + r'\\' + keyword + '_' + str(num) + '.jpg'
            fp = open(string, 'wb')
            fp.write(pic.content)
            fp.close()
            num += 1
        if num >= numPicture:
            return


if __name__ == '__main__':  # 主函数入口
    ##############################
    # 这里加了点
    headers = {
        'Accept-Language': 'zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2',
        'Connection': 'keep-alive',
        'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Firefox/60.0',
        'Upgrade-Insecure-Requests': '1'
    }

    A = requests.Session()
    A.headers = headers
    ###############################
    word = input("请输入搜索关键词(可以是人名,地名等): ")
    # add = 'http://image.baidu.com/search/flip?tn=baiduimage&ie=utf-8&word=%E5%BC%A0%E5%A4%A9%E7%88%B1&pn=120'
    url = 'https://image.baidu.com/search/flip?tn=baiduimage&ie=utf-8&word=' + word + '&pn='

    # 这里搞了下
    tot = Find(url, A)
    Recommend = recommend(url)  # 记录相关推荐
    print('经过检测%s类图片共有%d张' % (word, tot))
    numPicture = int(input('请输入想要下载的图片数量 '))
    file = input('请建立一个存储图片的文件夹,输入文件夹名称即可')
    y = os.path.exists(file)
    if y == 1:
        print('该文件已存在,请重新输入')
        file = input('请建立一个存储图片的文件夹,)输入文件夹名称即可')
        os.mkdir(file)
    else:
        os.mkdir(file)
    t = 0
    tmp = url
    while t < numPicture:
        try:
            url = tmp + str(t)
            # 这里搞了下
            result = A.get(url, timeout=10, allow_redirects=False)

        except error.HTTPError as e:
            print('网络错误,请调整网络后重试')
            t = t + 60
        else:
            dowmloadPicture(result.text, word)
            t = t + 60
    print('当前搜索结束,感谢使用')
    print('猜你喜欢')

    for re in Recommend:
        print(re, end='  ')

需要你安装bs4 ,用pip install bs4就行,缺啥就pip install啥~