美文网首页
python 爬虫学习之requests库的response对象

python 爬虫学习之requests库的response对象

作者: _Mirage | 来源:发表于2020-03-30 04:28 被阅读0次
首先这些都会尝试下: 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()

相关文章

网友评论

      本文标题:python 爬虫学习之requests库的response对象

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