Python爬虫抓取百度搜索图片

最近玩机器学习,想搞一个关于识别动漫图片的训练集,苦于没有太多的动漫图片,后来忽然想到百度图片可以拿来用,于是乎写了个简单的爬虫,用来抓取百度图片(关于某个关键字的图片)

第一步,找到搜索图片的url。

打开百度图片网页,搜索“高清动漫”,审查元素,检查network,清空network请求数据,滚动网页到底部,看到它自动加载更多了,然后在network请求里找到关于加载更多数据的url。像是这样http://image.baidu.com/search/acjson?tn=resultjson_com&ipn=rj&ct=201326592&is=&fp=result&queryWord=%E9%AB%98%E6%B8%85%E5%8A%A8%E6%BC%AB&cl=2&lm=-1&ie=utf-8&oe=utf-8&adpicid=&st=-1&z=&ic=0&word=%E4%BA%8C%E6%AC%A1%E5%85%83&s=&se=&tab=&width=&height=&face=0&istype=2&qc=&nc=1&fr=&pn=60&rn=30&gsm=1000000001e&1486375820481=

对比了几个加载更多的url发现,rn参数是每页的显示个数,pn参数是已经请求到的数量。通过修改rn参数及pn参数,观察返回的数据,发现每页最多只能是60,也就是rn最大设置为60.

第二步,分析返回数据。

把上面的url通过浏览器请求,在页面上看到一个超级到的json,分析后发现图片的url是thumbURL middleURL hoverurl这三个属性,搜索一下这三个属性在返回字符串中的数量,发现数量刚好与分页的数量一样。拿这三个url通过浏览器打开,发现thumburl比middleUrl大,与hoverUrl是同一个url。其实还有个objUrl(原图)可以用,不过该url不稳定,有时候会404,有时候会拒绝访问。

然后是码代码

我的python版本是2.7

更新于2017年2月11日
1.保存的图片改为原高清大图 OjbUrl
2.修改使用方法,搜索的关键字可以从命令行输入了
3.随时保存,不再是先搜索所有的图片才保存了。

BaiduImageSearch.py

#coding=utf-8
from urllib import quote
import urllib2 as urllib
import re
import os


class BaiduImage():

    def __init__(self, keyword, count=2000, save_path="img", rn=60):
        self.keyword = keyword
        self.count = count
        self.save_path = save_path
        self.rn = rn

        self.__imageList = []
        self.__totleCount = 0

        self.__encodeKeyword = quote(self.keyword)
        self.__acJsonCount = self.__get_ac_json_count()

        self.user_agent = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.95 Safari/537.36"
        self.headers = {'User-Agent': self.user_agent, "Upgrade-Insecure-Requests": 1,
                        "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
                        "Accept-Encoding": "gzip, deflate, sdch",
                        "Accept-Language": "zh-CN,zh;q=0.8,en;q=0.6",
                        "Cache-Control": "no-cache"}
        # "Host": Host,

    def search(self):
        for i in range(0, self.__acJsonCount):
            url = self.__get_search_url(i * self.rn)
            response = self.__get_response(url).replace("\\", "")
            image_url_list = self.__pick_image_urls(response)
            self.__save(image_url_list)

    def __save(self, image_url_list, save_path=None):
        if save_path:
            self.save_path = save_path

        print "已经存储 " + str(self.__totleCount) + "张"
        print "正在存储 " + str(len(image_url_list)) + "张,存储路径:" + self.save_path

        if not os.path.exists(self.save_path):
            os.makedirs(self.save_path)

        for image in image_url_list:
            host = self.get_url_host(image)
            self.headers["Host"] = host

            with open(self.save_path + "/%s.jpg" % self.__totleCount, "wb") as p:
                try:
                    req = urllib.Request(image, headers=self.headers)
                    # 设置一个urlopen的超时,如果10秒访问不到,就跳到下一个地址,防止程序卡在一个地方。
                    img = urllib.urlopen(req, timeout=20)
                    p.write(img.read())
                    p.close()
                    self.__totleCount += 1
                except Exception as e:
                    print "Exception" + str(e)
                    p.close()
                    if os.path.exists("img/%s.jpg" % self.__totleCount):
                        os.remove("img/%s.jpg" % self.__totleCount)

        print "已存储 " + str(self.__totleCount) + " 张图片"

    def __pick_image_urls(self, response):
        reg = r'"ObjURL":"(http://img[0-9]\.imgtn.*?)"'
        imgre = re.compile(reg)
        imglist = re.findall(imgre, response)
        return imglist

    def __get_response(self, url):
        page = urllib.urlopen(url)
        return page.read()

    def __get_search_url(self, pn):
        return "http://image.baidu.com/search/acjson?tn=resultjson_com&ipn=rj&ct=201326592&is=&fp=result&queryWord=" + self.__encodeKeyword + "&cl=2&lm=-1&ie=utf-8&oe=utf-8&adpicid=&st=-1&z=&ic=0&word=" + self.__encodeKeyword + "&s=&se=&tab=&width=&height=&face=0&istype=2&qc=&nc=1&fr=&pn=" + str(pn) + "&rn=" + str(self.rn) + "&gsm=1000000001e&1486375820481="

    def get_url_host(self, url):
        reg = r'http://(.*?)/'
        hostre = re.compile(reg)
        host = re.findall(hostre, url)
        if len(host) > 0:
            return host[0]
        return ""

    def __get_ac_json_count(self):
        a = self.count % self.rn
        c = self.count / self.rn
        if a:
            c += 1
        return c

使用实例
run.py

#coding=utf-8
from BaiduImageSearch import BaiduImage
import sys


keyword = " ".join(sys.argv[1:])
save_path = "_".join(sys.argv[1:])

if not keyword:
    print "亲,你忘记带搜索内容了哦~ 搜索内容关键字可多个,使用空格分开"
    print "例如:python run.py 男生 头像"
else:
    search = BaiduImage(keyword, save_path=save_path)
    search.search()

ps:两个文件的同一目录下记得加上_init_.py文件!!!
运行方法,python run.py 关键字1 关键字2 关键字3…

一般搜索到1900多张的时候就没了。

欢迎加微信交流Python及机器学习。微信号:nime__mine 两个下划线

    原文作者:dodouaj
    原文地址: https://blog.csdn.net/dodouaj/article/details/54908665
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞