zoukankan      html  css  js  c++  java
  • 爬虫请求库之requests库

    一. 介绍#

    Copy
    # 介绍:使用requests可以模拟浏览器的请求,比起之前用到的urllib,requests模块的api更加便捷(本质就是封装了urllib3)
    
    # 注意:requests库发送请求将网页内容下载下来以后,并不会执行js代码,这需要我们自己分析目标站点然后发起新的request请求
    
    # 安装:pip3 install requests
    
    # 各种请求方式:常用的就是requests.get()和requests.post()
        >>> import requests
        >>> r = requests.get('https://api.github.com/events')
        >>> r = requests.post('http://httpbin.org/post', data = {'key':'value'})
        >>> r = requests.put('http://httpbin.org/put', data = {'key':'value'})
        >>> r = requests.delete('http://httpbin.org/delete')
        >>> r = requests.head('http://httpbin.org/get')
        >>> r = requests.options('http://httpbin.org/get')
    
    # 建议在正式学习requests前,先熟悉下HTTP协议
        http://www.cnblogs.com/linhaifeng/p/6266327.html
    

    二. 基于GET请求#

    1. 发送get请求#

    知识储备: 什么是referer?

    Copy
    import requests
    
    headers = {
        # 模拟浏览器
        'user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36',
        # 解决妹子图防盗链问题: referer
        'referer': 'https://www.mzitu.com/taiwan/'
    }
    
    # response = requests.get('https://mzitu.com', headers=headers)
    # print(response.text)      # 文本内容
    
    response1 = requests.get("https://i.mmzztt.com/thumb/2020/07/221376_236.jpg", headers=headers)
    # print(response1.content)  # 二进制内容
    
    # 将爬取的图片写入本地
    with open('221376_236.jpg', 'wb') as f:
        for line in response1.iter_content():
            f.write(line)
    

    2. 请求地址中携带数据#

    1) 请求地址中携带数据方式一: 直接携带 (中文一般不会进行url编码, 会出现编码问题)#

    Copy
    import requests
    
    headers = {
        # 模拟浏览器
        'user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36',
    }
    response = requests.get('https://www.baidu.com/s?wd=wozhengshuai', headers=headers)
    print(response.text)
    

    2) 请求地址中携带数据方式二: 使用params (中文会自动进行url编码)#

    Copy
    import requests
    
    headers = {
        # 模拟浏览器
        'user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36',
    }
    response = requests.get('https://www.baidu.com/s', params={'wd': '我真帅'}, headers=headers)
    print(response.text)
    

    3) 使用urllib解决方式一编码问题#

    Copy
    from urllib.parse import urlencode, unquote
    
    
    # 编码
    res = urlencode({'wd': '我真帅'}, encoding='utf-8')
    print(res)  # wd=%E6%88%91%E7%9C%9F%E5%B8%85
    
    # 解码
    res = unquote('%E6%88%91%E7%9C%9F%E5%B8%85', encoding='utf-8')
    print(res)  # 我真帅
    

    3. 请求带cookie#

    1) 方式一: 存放在header#

    Copy
    import requests
    
    headers = {
        'user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.105 Safari/537.36',
        'cookie': 'Hm_lvt_b72418f3b1d81bbcf8f99e6eb5d4e0c3=1596202661; UM_distinctid=173a517b3192a1-07d51af695c35e-3a65420e-1fa400-173a517b31a70b;'
    }
    
    # 注意: url不要写错成了 'http://127.0.0.1:8050/index'
    response = requests.get('http://127.0.0.1:8050/index/', headers=headers)
    print(response.text)
    # 服务端获取: 
    # 注意: 放在headers中, cookie对应的value如果有等于号, 那么等于号左边作为cookie的key, 右边作为cookie的value. 如果没有那么, key为空字符串. value为值.
    """
    {
        'Hm_lvt_b72418f3b1d81bbcf8f99e6eb5d4e0c3': '1596202661', 
        'UM_distinctid': '173a517b3192a1-07d51af695c35e-3a65420e-1fa400-173a517b31a70b'
    } 
    """
    

    2) 方式二: 存放在指定的cookies参数中#

    Copy
    import requests
    
    headers = {
        'user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.105 Safari/537.36',
    }
    cookies = {
        'cookie': 'Hm_lvt_b72418f3b1d81bbcf8f99e6eb5d4e0c3=1596202661; UM_distinctid=173a517b3192a1-07d51af695c35e-3a65420e-1fa400-173a517b31a70b;'
    }
    
    # 注意: url不要写错成了 'http://127.0.0.1:8050/index'
    response = requests.get('http://127.0.0.1:8050/index/', headers=headers, cookies=cookies)
    print(response.text)
    
    # 服务端获取: 
    # 注意: cookies直接指定. 字典中的key对应的服务端cookie获取的key. 字典中value冒号分隔的等于号左边作为cookie的key, 右边作为value
    '''
    {
        'cookie': 'Hm_lvt_b72418f3b1d81bbcf8f99e6eb5d4e0c3=1596202661', 
        'UM_distinctid': '173a517b3192a1-07d51af695c35e-3a65420e-1fa400-173a517b31a70b'
    }
    

    4. 总结#

    Copy
    # headers参数: 
        1. 模拟浏览器: user-agent
        2. 解决防盗链: referer
    
    # 解决url编码问题
        1. params参数默认解决url编码问题 
        2. urllib模块
        
    # 携带cookie
        第一种方式: 存放在headers中
        客户端发送: {'cookie': 'key=value;key1=value1'}
        服务端获取: {key: value, key1: value1} 
    
        第二种方式: 指定cookie参数 (提示: 可以存放dict 和 CookieJar对象)
            客户端发送: {key: value, key1: value1}
            服务端获取: {key: value, key1: value1}   
        
    response.text  文本
    response.content  二进制
    response.iter_content()  迭代器
    

    三. 基于POST请求#

    1. 携带数据发送post请求#

    1) 携带数据: urlencoded#

    Copy
    import requests
    
    response = requests.post('http://127.0.0.1:8050/index/', data={'name': 'yang'})
    print(response.text)
    
    # 服务端获取
    '''
    request.body: b'name=yang'
    request.POST: <QueryDict: {'name': ['yang']}>
    '''
    

    2) 携带数据: json#

    Copy
    import requests
    
    response = requests.post('http://127.0.0.1:8050/index/', json={'name': 'yang'})
    print(response.text)
    
    # 服务端获取
    '''
    request.body: b'{"name": "yang"}'
    request.POST: <QueryDict: {}>
    '''
    

    2. 自动携带cookie#

    Copy
    import requests
    
    session = requests.session()      # 注意: 是session()方法, 不是sessions()
    session.post('http://127.0.0.1:8050/login/', json={'username': 'yang', 'password': '123'})          # 假设这个请求登录了
    response = session.get('http://127.0.0.1:8050/index/')  # 现在不需要手动带cookie, session会自动处理
    print(response)
    

    3. 自定义请求头#

    Copy
    requests.post(url='xxxxxxxx',
                  data={'xxx': 'yyy'})  # 没有指定请求头,# 默认的请求头:application/x-www-form-urlencoed
    
    # 如果我们自定义请求头是application/json,并且用data传值, 则服务端取不到值
    requests.post(url='',
                  data={'': 1, },
                  headers={
                      'content-type': 'application/json'
                  })
    
    requests.post(url='',
                  json={'': 1, },
                  )  # 默认的请求头:application/json
    

    4. 总结#

    Copy
    # 携带数据:
        携带json数据: json={}
        携带urlencoded数据: data={}
        
    # 自动携带cookie:     
        session = requests.session()
        res = session.post(认证url)
        res1 = session.get(访问url)
        
    # 自定义请求头:
        默认: application/x-www-form-urlencoed
        headers={'content-type': 'application/json'}  
    

    四. 响应Response#

    1. response对象方法#

    Copy
    import requests
    
    response = requests.post('http://127.0.0.1:8050/index/?username=yang', data={'name': 'yang'})
    
    # 响应的文本
    res = response.text
    print(res)  # ok
    
    # 响应体的二进制
    res = response.content
    print(res)  # b'ok'
    
    # 获取响应状态码
    res = response.status_code
    print(res)  # 200
    
    # 获取响应头
    res = response.headers
    print(res)
    '''
    {
        'Date': 'Fri, 31 Jul 2020 14:32:06 GMT', 'Server': 'WSGIServer/0.2 CPython/3.6.3', 
        'Content-Type': 'application/json', 
        'X-Frame-Options': 'SAMEORIGIN', 
        'Content-Length': '16', 
        'Set-Cookie': 'cookie_key=cookie_value; Path=/'
    }
    '''
    
    # 注意: 它是CookieJar对象, 获取后端设置的cookie
    res = response.cookies
    print(res)   # <RequestsCookieJar[<Cookie cookie_key=cookie_value for 127.0.0.1/>]>
    
    # 把cookie转成字典
    res = response.cookies.get_dict()
    print(res)  # {'cookie_key': 'cookie_value'}
    
    # 把cookie转成列表套元组
    res = response.cookies.items()
    print(res)  # [('cookie_key', 'cookie_value')]
    
    # 获取请求的url地址
    res = response.url
    print(res)  # http://127.0.0.1:8050/index/?username=yang 如果重定向了那么就是重定向的地址 http://127.0.0.1:8050/home/
    
    
    # 将重定向之前的地址存放到列表当中. 注意: 是response对象
    res = response.history
    print(res)             # [<Response [302]>, <Response [302]>]
    print(type(res[0]))    # <class 'requests.models.Response'>
    print(res[0].content)  # b''
    
    # 响应的编码方式
    res = response.encoding
    print(res)  # ISO-8859-1
    
    # iter_content主要是针对图片,视频,大文件. 可以迭代取值
    res = response.iter_content()
    print(res)   # <generator object iter_slices at 0x0000021A72B5F360>
    

    2. 编码问题#

    Copy
    import requests
    
    response = requests.get('http://www.autohome.com/news')
    # 方式一: 手动指定编码 (前提: 知道它的编码方式)
    # response.encoding = 'gb2312'
    
    # 方式二: 自动指定编码, 由方法内部获取.
    response.encoding = response.apparent_encoding
    print(response.text)
    

    3. 解析json#

    Copy
    import requests
    
    response = requests.post('http://127.0.0.1:8050/index/', data={'name': 'yang'})
    response_text = response.text
    print(type(response_text), response_text)  # <class 'str'> {"name": "yang"}
    
    # 解析方式一: 使用json模块解析 (繁琐)
    import json
    res = json.loads(response_text)
    print(type(res), res)  # <class 'dict'> {'name': 'yang'}
    
    # 解析方式二: 使用requests提供的方法解析(提示: 内部本质还是调用了json)
    res = response.json()
    print(type(res), res)  # <class 'dict'> {'name': 'yang'}
    
    # 注意: 方式一是通过获取到文本内容再进行的json序列化, 而方式二是直接透过response对象调用json()方法.
    

    4. 总结#

    Copy
    # response对象方法: 
        响应文本                      response.text      
        响应二进制数据                 response.content
        响应状态码                    response.status_code
        响应头                        response.headers
        响应CookieJar对象             response.cookies
        响应cookie字典                response.cookies.get_dict()
        响应cookie列表套元组           response.cookies.items()
        响应重定向之前的response对象    response.history
        响应url地址                   response.url
        响应编码                      response.encoding
        响应数据的迭代器               response.iter_content()
        
    # 解决响应内容编码: 
        手动: response.encoding = '你知道你获取url资源的编码'
        自动: response.encoding = response.apparent_encoding
        
    # 解析json:
        1. json模块解析
            json.loads(response.text)
        2. requests提供的json()方法解析
            response.json()
    

    五. 高级用法#

    1. SSL Cerf Verification#

    Copy
    import requests
    
    response = requests.get('https://www.12306.cn', verify=False)
    print(response.status_code)  # 不验证证书,报警告,返回200
    
    
    # 使用证书,需要手动携带
    import requests
    
    response = requests.get('https://www.12306.cn',
                            cert=('/path/server.crt',
                                  '/path/key'))
    print(response.status_code)
    

    2. 使用代理#

    知识储备: 什么是http代理,什么是socks5代理?两者有什么不同?

    1) HTTP代理#

    Copy
    import requests
    response = requests.get('https://www.baidu.com/', proxies={'http': '165.225.8.94:10605', })
    print(response.status_code)
    

    2) socks代理#

    Copy
    # 安装: pip install requests[socks]
    import requests
    
    proxies = {
        # 'https': 'socks5://47.244.192.12:17518',
        'http': 'socks5://47.244.192.12:17518',
    }
    
    response = requests.get('https://www.baidu.com',
                            proxies=proxies)
    
    print(response.status_code)
    

    3. 超时设置#

    Copy
    import requests
    
    # 两种超时:float or tuple
    # timeout = 0.001  # 代表接收数据的超时时间
    timeout = (0.0001, 0.002)  # 0.1代表链接超时  0.2代表接收数据的超时时间
    response = requests.get('https://www.baidu.com',
                            timeout=timeout)
    print(response.text)
    print(response.status_code)
    # 注意: 超时以后抛出异常. 
    '''
    # 0.0001表示链接超时
    requests.exceptions.ReadTimeout: HTTPSConnectionPool(host='www.baidu.com', port=443): Read timed out. (read timeout=0.0001)
    '''
    

    4. 认证设置#

    官网链接:http://docs.python-requests.org/en/master/user/authentication/

    Copy
    '''
    认证设置:登陆网站是,弹出一个框,要求你输入用户名密码(与alter很类似),此时是无法获取html的
    但本质原理是拼接成请求头发送
            r.headers['Authorization'] = _basic_auth_str(self.username, self.password)
    一般的网站都不用默认的加密方式,都是自己写
    那么我们就需要按照网站的加密方式,自己写一个类似于_basic_auth_str的方法
    得到加密字符串后添加到请求头
            r.headers['Authorization'] =func('.....')
    '''
    
    # 看一看默认的加密方式吧,通常网站都不会用默认的加密设置
    import requests
    from requests.auth import HTTPBasicAuth
    
    r = requests.get('xxx', auth=HTTPBasicAuth('user', 'password'))
    print(r.status_code)
    
    # HTTPBasicAuth可以简写为如下格式
    import requests
    
    r = requests.get('xxx', auth=('user', 'password'))
    print(r.status_code)
    

    5. 异常处理#

    Copy
    import requests
    from requests.exceptions import *
    
    try:
        response = requests.get('https://www.baidu.com', timeout=(0.001, 0.002))
        print(response.status_code)
    except ReadTimeout:
        print('读取超时!')
    except ConnectionError:
        print('连接失败!')
    except Timeout:
        print('超时')
    except RequestException:
        print("请求异常")
    except Exception as e:
        print(e)
    

    6. 上传文件#

    Copy
    import requests
    import  os
    
    dir_path = os.path.join(os.path.dirname(__file__), '2')
    dir_list = os.listdir(dir_path)
    file1, file2 = dir_list[0], dir_list[1]
    # print(file1, file2)  # 220089_236.jpg 220304_236.jpg
    file1_path = os.path.join(dir_path, file1)
    file2_path = os.path.join(dir_path, file2)
    
    files = {
        'file1': open(file1_path, 'rb'),
        'file2': open(file2_path, 'rb'),
    }
    response = requests.post('http://127.0.0.1:8050/index/', files=files)
    print(response.status_code)  # 200
      
    # 后端数据获取: 
    '''
    <MultiValueDict: 
        {
        'file1': [<InMemoryUploadedFile: 220089_236.jpg ()>], 
        'file2': [<InMemoryUploadedFile: 220304_236.jpg ()>]
        }
    >
    '''
    

    7. 总结#

    Copy
    # SSL认证
        verify=False不校验
        verify=True校验.  cert=(证书格式)
        
    # 代理
        # HTTP代理
        proxies={'http': 'IP:PORT'}
        
        # socks代理: 安装requests[socks]
        proxies={'http': 'socks://IP:PORT'}
        
    # 超时设置
        timeout=(连接超时时间, 接受数据超时时间)
        抛出异常: ReadTimeOut
    
    # 认证设置
        from requests.auth import HTTPBasicAuth
        auth=HTTPBasicAuth('user', 'password')
        
    # 异常处理
        from requests.exceptions import *
        ReadTimeOut       连接 或者 获取数据超时
        TimeOut           超时
        ConnectionError   连接错误
        RequestException  请求异常 
        
    # 上传文件
        files={key: file, key1: file1}   
    
  • 相关阅读:
    谈执着
    SQL表自连接用法
    Mysql group by 排序问题
    php自动生成mysql的触发代码。
    XSS CSRF 攻击
    [微信开发利器]微信内移动前端开发抓包调试工具fiddler使用教程
    微信JS-SDK]微信公众号JS开发之卡券领取功能详解
    优化与重构的思考
    c语言 13
    c语言 13
  • 原文地址:https://www.cnblogs.com/Tornadoes-Destroy-Parking-Lots/p/13504095.html
Copyright © 2011-2022 走看看