python 爬虫学习之requests库的response对象学习(顺便爬取百度图片)

首先这些都会尝试下:
image.png

爬百度图片和之前爬搜狗图片一样,都没啥难度,只是想学习巩固下response对象的各个属性。

  1. text:
    返回值是字符串类型,本质上就是content返回的字节的解码。

    text其实不知道别人网站是用的什么编码格式,它解码的时候其实是“猜”的:
    image.png

    当然,大多数时候可以猜测正确,但是少数时候可能猜测错误,所以尽量少用text,多用content然后自己对字节文件解码。 或者你在调用text前手动设置解码格式:用response对象的encoding属性:
    image.png

    比如这里,我先查看要爬的网站:百度图片的meta标签里的charset属性:
    image.png

    现在我知道了网站是utf-8编码,然后我可以这样:
    image.png

    这样是没问题的:有正确的结果:
    image.png
  2. content:
    返回值是bytes类型,也就是字节流:


    image.png

没有任何问题:
image.png

检查一下:%B9%D8%CF%FE%CD%AE这个一看就是urlencoded格式的数据,我们手动解码看下:
image.png

注意解码格式要选gbk,我也不知道为啥,可能百度网页源码是utf-8编码,域名解析后是gbk,算了不重要。
\xe5\x85\xb3\xe6\x99\x93\xe5\xbd\xa4这个就是bytes类型的数据了,我们解码下:
image.png

也是对的。

3.查看请求头:


image.png

image.png

这里可以很明显的看到如果你不加user-agent的话:python会自动帮你加一个带有python字样的user-agent:
image.png
,所以别人很容易从请求头判断出你是不是爬虫,然后封你的ip,所以保持一个良好的习惯,每次写爬虫的时候都加上user-agent。

4.请求的cookie:

image.png

这样查看请求的cookies,注意这里一定要加上代表私有属性,不加的话访问不到cookies属性: 结果:
image.png

因为我访问的时候确实没加cookies,也没去抓取,所以这是对的。

  1. 响应头:


    image.png

    响应头就是这个:
    image.png

    你在抓包的时候会经常看到。
    程序结果:
    image.png

    响应头其实是很有用的,很多cookies都是在响应头里面设置的:
    image.png

    就有的时候你登陆之后获取一次cookie, 然后光靠这个cookie如果要抓取更里面的数据可能会抓不到,因为正常人访问不是一下直接访问到最后,而是一个网站一个网站的往里面点进去,然后每点一个网站它都会给你设置cooke,这些cookie对于访问更后面的网站必不可少的。
    比如我爬我学校官网就是这样,光靠登陆获取的cookie访问不到成绩,必须要模拟登录两次,第一次登陆到主界面获取一次cooke,第二次登陆到成绩网站里面去再获取一次cooke,然后通过这些累加的cooke最后才能直接访问到成绩。

6.响应的cookie
requests库真的特别人性化,利用它的response.cookies直接可以查看别人在响应头给我们设置的cookie:


image.png

注意这里的cookies属性不是私有属性,前面不需要加_。

结果:
image.png

可以看到访问这个网站,别人确实给我们设置了cookie,当然大多数网站不会设置cookie,登陆网站,或者不想让你这么容易爬到数据就可以设置很多cookie,这时候你就必须要一个网站一个网站去登陆获取保存cookie,具体要登陆哪些网站通过抓包分析。

7.响应的状态码:


image.png

所谓响应码就是服务器返回给你的一个判别码,不同码有不同的含义,200是大家最想看到的,代表成功访问,还有很多别的,比如404not found, 就是没找到服务器等等,这里发个百度到的响应状态码表:
image.png

大概这么多,记住几个常用的就ok了。
当然我们程序返回的是200:
image.png

8.实际请求的url,因为这里我们程序请求时候是通过params参数传递自动拼接的,如果想查看拼接后的url,就要用reponse.url查看:
image.png

我们初始传递的只是:
image.png

requests帮我们拼接后变成了:
image.png

而且在拼接的过程中requests还帮我们把非urlencoded类型的数据自动转译了,不需要我们像用urllib.request库那样手动用 urllib.request.urlencode来手动把字典格式数据转成urlencoded格式。

大概要学习的reponse对象就这么多。

剩下的爬取就比较简单了。
因为别人返回的直接是json,直接转成字典就欧克了:


image.png

注意结果列表里每一个元素都是个字典:
image.png

包含了很多键,也有很多url,我们用哪个呢?英语好的一看thumb就是拇指的意思,意思就是这个url装的肯定不是高清原图,肯定是压缩变小后的图,不清晰,不能用这个,middleurl和拇指url一样最好不用。
我们最后就发现了一个个objurl,这个其实就是最终的答案,但是为什么它长得不像url?-------->>>>>原因就是百度给他用特定的算法加密了,不想让你这么轻松的爬到数据,然后我首先知道它的解密算法肯定隐藏在某个js文件中,后来我好像找到了,可能是这个:
image.png

这个js文件 好多url名称和关键字的映射:


image.png

image.png

但是他写的实在是太复杂了,好多好多函数,我没分析出来。

其实这个解密算法网上也有牛人早就搞出来了,直接搜就可以了,前人栽树后人乘凉:
image.png

直接用就好了,这个加密算法其实就是一些字母的映射。
清楚了这些,就好搞了,总结下,返回类型json,导入python字典,获取data键下的列表,里面是所有元素,然后在每个元素里找出objurl的键在用解密算法解密就可以了。

运行结果:
image.png

源代码:

# coding='utf-8'

import re
import requests
from lxml import etree
import os


class Spider:
    '''用来爬取百度图片同时学习response对象的用法'''
    def __init__(self, url='', path=''):
        self.url = url if url else 'https://image.baidu.com/search/acjson'
        self.path = path if path else './百度图片/'
        # 爬哪一页
        self.page = 0
        # 爬啥
        self.name = input('输入关键字:')
        # 图片格式
        self.image_fmt = ['.jpg', '.png', '.gif', '.jpeg',]
        # 拼接参数
        self.params = {
            'tn': 'resultjson_com',
            'ipn': 'rj',
            'word': self.name,
            'pn': self.page,
        }
        # 下载失败的次数
        self.fail_times = 0
        # 用户输入下载数
        self.input_number = int(input('输入下载数量:'))
    # 用来对加密的百度图片解码,,网上搜的,我分析了半天实在没分析出来
    def decode_url(self, url):
        """
        对百度加密后的地址进行解码\n
        :param url:百度加密的url\n
        :return:解码后的url
        """
        table = {'w': "a", 'k': "b", 'v': "c", '1': "d", 'j': "e", 'u': "f", '2': "g", 'i': "h",
                 't': "i", '3': "j", 'h': "k", 's': "l", '4': "m", 'g': "n", '5': "o", 'r': "p",
                 'q': "q", '6': "r", 'f': "s", 'p': "t", '7': "u", 'e': "v", 'o': "w", '8': "1",
                 'd': "2", 'n': "3", '9': "4", 'c': "5", 'm': "6", '0': "7",
                 'b': "8", 'l': "9", 'a': "0", '_z2C$q': ":", "_z&e3B": ".", 'AzdH3F': "/"}
        url = re.sub(r'(?P<value>_z2C\$q|_z\&e3B|AzdH3F+)', lambda matched: table.get(matched.group('value')), url)
        return re.sub(r'(?P<value>[0-9a-w])', lambda matched: table.get(matched.group('value')), url)

    # 根据给定的url获得它的etree对象
    def get_etree(self, url):
        pass

    # 根据给定的待解析数据target和格式字符串fmt解析数据
    def parse_data(self, target, fmt=''):
        return

    # 根据给定url,利用requests库获得它的response对象
    def get_response(self, url, params=''):
        headers = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.149 Safari/537.36',
        }
        cnt = 0
        total_times = 10
        while True:
            # 如果一分钟还没有数据就退出
            if cnt >= total_times:
                print('*************\n\n由于各种原因,第{}张图下载失败\n\n**************'.format(self.image_number))
                self.image_number += 1
                self.fail_times += 1
                return None
            try:
                if params:
                    response = requests.get(url, params=params, headers=headers,
                                            timeout=2)
                else:
                    response = requests.get(url, headers=headers, timeout=2)
                return response
            except Exception as e:
                cnt += 1
                print('可能是网络问题,正在进行第{}次尝试..(一共尝试{}次.)'.format(cnt, total_times))

    # 根据response对象测试它的各个属性
    def test_response(self, response):
        # 测试text (是程序猜测的编码格式之后用猜测的编码格式解码)
        response.encoding = 'utf-8'
        text = response.text
        # print(text)
        # 测试content(返回值bytes类型)
        content = response.content
        # print(content)
        # 查看请求头
        request_headers = response.request.headers
        # print(request_headers)
        # 请求的cookie
        request_cookies = response.request._cookies
        # print(request_cookies)
        # 响应头
        response_headers = response.headers
        # print(response_headers)
        # 直接查看响应头的cookie
        response_cookies = response.cookies
        # print(response_cookies)
        # 查看响应状态码
        response_code = response.status_code
        # print(response_code)
        # 查看完整请求url
        complete_url = response.url
        # print(complete_url)

    # 给根据给定的图片url将图片下载到本地
    def download(self, obj_list, path=''):
        for each in obj_list:
            try:
                temp_str = each[each.rfind('.'):]
                if temp_str in self.image_fmt:
                    end_fmt = temp_str
                else:
                    end_fmt = self.image_fmt[0]
                if os.path.exists(path+str(self.image_number)+end_fmt):
                    print('路径下已存在{}:{}'.format(self.image_number, each))
                    if self.image_number >= self.input_number:
                        self.flag = False
                        break
                    self.image_number += 1
                    continue
            except Exception as e:
                end_fmt = self.image_fmt[0]
            response = self.get_response(each)
            if response:
                with open(path+str(self.image_number)+end_fmt, 'wb') as f:
                    f.write(response.content)
                print('成功下载{}:{}'.format(self.image_number, each))
                if self.image_number >= self.input_number:
                    self.flag = False
                    break
                self.image_number += 1
        else:
            return
        print('\n^^^^&&^^^^{}张图片下载完毕!,成功下载了{}张, 下载失败了{}张..'.format(self.input_number, self.image_number-self.fail_times, self.fail_times))
        os._exit(0)


    # 给一个json对象,返回url构成的列表
    def download_from_json(self, data):
        url_list = []
        for each in data['data']:
            try:
                url_list.append(self.decode_url(each['objURL']))
            except Exception as e:
                pass
        return url_list

    # 类从这里开始
    def start(self):
        # 正在下载第几张图片
        self.image_number = 1
        # target = self.get_etree(self.url)
        # result_list = self.parse_data(target)
        # self.download(result_list)
        # self.test_response(response)
        path = self.path+self.name+'/'
        if not os.path.exists(path):
            os.makedirs(path)
        while True:
            response = self.get_response(self.url, self.params).json()
            url_list = self.download_from_json(response)
            self.download(url_list, path)
            self.page += 30
            self.params['pn'] = self.page


Spider().start()
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,402评论 6 499
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,377评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,483评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,165评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,176评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,146评论 1 297
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,032评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,896评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,311评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,536评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,696评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,413评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,008评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,659评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,815评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,698评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,592评论 2 353

推荐阅读更多精彩内容

  • HTTP基本原理 URI、URL、URN(Uninform Resource) URI(Identifier):统...
    GHope阅读 2,076评论 2 26
  • 一 . Tomcat 1.对Tomcat的理解 Tomcat是一个运行JAVA的网络服务器,提供能够让别人访问自己...
    Vegetable蔬菜阅读 829评论 2 1
  • 本文整理自MIN飞翔博客 [1] 1. 概念 协议是指计算机通信网络中两台计算机之间进行通信所必须共同遵守的规定或...
    HoyaWhite阅读 2,671评论 2 20
  • 网络 理论模型,分为七层物理层数据链路层传输层会话层表示层应用层 实际应用,分为四层链路层网络层传输层应用层 IP...
    FlyingLittlePG阅读 766评论 0 0
  • 看了很多关于假装很努力的推文,发现每一篇都似是而非,所有文章讲的都是一句话,那就是: 你不是努力,只是看起来很努力...
    废_8076阅读 317评论 0 0