• 爬虫 >>> Requests 模块


    爬虫的定义

      向网站发起请求,获取资源后分析并提取 有用数据 (我们的爬虫程序只提取网页代码中对我们有用的数据)

    爬虫的基本流程

                       

    1、发起请求
        使用 http 库向目标站点发起请求,即发送一个 Request
        Request 包含:请求头、请求体等
        注:selenium 也是经常用到的模块,可以解析 html 页面
    
    2、获取响应内容
        如果服务器能正常响应,则会得到一个 Response
        Response 包含:html,json,图片,视频等
    
    3、解析内容
        解析 html 数据:正则表达式,第三方解析库如 Beautifulsoup,pyquery 等
        解析 json 数据:json 模块
        解析二进制数据:以 b 模式写入文件
    
    4、保存数据
        保存在数据库: MySQL, mongoDB, redis等
        或者文件中

     官网链接: https://2.python-requests.org//en/master/

     下载安装:pip3 install requests


     

    Requests

      1:发送 GET 和 POST 请求(常用) 

          使用 request 发送 get 和 post 请求,访问的数据都会拼接成这种形式:k1=xxx&k2=yyy&k3=zzz

          post 请求的参数存放在请求体中(可以用浏览器查看,存放于 form-data 中)

          get 请求的参数直接 放在 url 后面,可以直接查看到

       2:请求头

          User-Agent:绝大多数网站需要设置 User-Agent;缺失的话可能会将你当作非法用户

          在请求头内将自己伪装成浏览器,否则百度不会正常返回页面内容

          Cookies:用来保存登录信息

          Referer:访问当前链接的上一层链接(校验作用),用来判断请求来源

          Host: 不一定需要

    import requests
    
    response = requests.get/post(url, headers, cookie, params/data, stream)  
    '''
    url:要访问的路径
    headers:请求时候的请求头,一般要携带 User-Agent, Referer 等参数
    cookie:每次请求的 token 值,本质是包含在 headers 内,但为了方便,可以单独书写
    params:get 请求所携带的参数,会自动往要访问的 url 后面进行拼接(会暴露在浏览器的地址栏中)
    data:post 请求所携带的参数
    stream:访问视频资源较大时,设置参数为 True,可以一点一点获取资源,默认为 False
    ...
    '''

    补充:

     HTTP 默认的请求方式是 get 请求:
       get 请求没有请求体,数据必须在1k之内,并且数据会暴露在浏览器的地址栏中
       requests.post() 用法与 requests.get() 一致 

       GET 和 POST 的区别:

        

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

       响应相关

    response.encoding =  # 默认编码为ISO-8859-1(如若请求来的内容有中文,需要指定一下编码格式)
    response.status_code  # 相应状态码
    response.text  # 响应的内容文本
    response.content  # 响应的二进制数据:如图片,视频等资源
    response.headers  # 响应头信息
    response.cookies  # 相应回来的cookies
    response.cookies.get_dict()  # 获取cookies信息,值为字典形式
    response.cookies.items()
    response.url  # 响应回来的url
    response.history  # 发送响应到接收响应经过的所有url
    response.close()  # 关闭响应
    ...

      响应状态

        200:成功

        301:跳转

        404:资源不存在

        403:权限不足

        502:服务器错误

       解析 json

    import requests
    import json
    
    response=requests.get('http://httpbin.org/get')
    res1 = json.loads(response.text)  # 太麻烦
    res2 = response.json()  # 直接获取 json 数据
    print(res1 == res2)  # 结果为 True

       例子:爬取校花网视频

    import requests
    import re
    import time
    import hashlib
    
    
    def get_page(url):
        print('GET %s' % url)
        try:
            response = requests.get(url)
            if response.status_code == 200:
                return response.content
        except Exception:
            pass
    
    def parse_index(res):
        obj = re.compile('class="items.*?<a href="(.*?)"', re.S)
        detail_urls = obj.findall(res.decode('gbk'))
        for detail_url in detail_urls:
            if not detail_url.startswith('http'):
                detail_url = 'http://www.xiaohuar.com' + detail_url
            yield detail_url
    
    def parse_detail(res):
        obj = re.compile('id="media".*?src="(.*?)"', re.S)
        res = obj.findall(res.decode('gbk'))
        if len(res) > 0:
            movie_url = res[0]
            return movie_url
    
    def save(movie_url):
        response = requests.get(movie_url, stream=False)
        if response.status_code == 200:
            m = hashlib.md5()
            m.update(('%s%s.mp4' % (movie_url, time.time())).encode('utf-8'))
            filename = m.hexdigest()
            with open(r'./movies/%s.mp4' % filename, 'wb') as f:
                f.write(response.content)
                f.flush()
    
    def main():
        index_url = 'http://www.xiaohuar.com/list-3-{0}.html'
        for i in range(5):
            print('*' * 50, i)
            # 爬取主页面
            index_page = get_page(index_url.format(i, ))
            # 解析主页面,拿到视频所在的地址列表
            detail_urls = parse_index(index_page)
            # 循环爬取视频页
            for detail_url in detail_urls:
                # 爬取视频页
                detail_page = get_page(detail_url)
                # 拿到视频的url
                movie_url = parse_detail(detail_page)
                if movie_url:
                    # 保存视频
                    save(movie_url)
    
    if __name__ == '__main__':
        main()
    
        
    # 并发爬取
    from concurrent.futures import ThreadPoolExecutor
    import queue
    import requests
    import re
    import time
    import hashlib
    from threading import current_thread
    
    
    p = ThreadPoolExecutor(50)
    def get_page(url):
        print('%s GET %s' % (current_thread().getName(), url))
        try:
            response = requests.get(url)
            if response.status_code == 200:
                return response.content
        except Exception as e:
            print(e)
    
    def parse_index(res):
        print('%s parse index ' % current_thread().getName())
        res = res.result()
        obj = re.compile('class="items.*?<a href="(.*?)"', re.S)
        detail_urls = obj.findall(res.decode('gbk'))
        for detail_url in detail_urls:
            if not detail_url.startswith('http'):
                detail_url = 'http://www.xiaohuar.com' + detail_url
            p.submit(get_page, detail_url).add_done_callback(parse_detail)
    
    def parse_detail(res):
        print('%s parse detail ' % current_thread().getName())
        res = res.result()
        obj = re.compile('id="media".*?src="(.*?)"', re.S)
        res = obj.findall(res.decode('gbk'))
        if len(res) > 0:
            movie_url = res[0]
            print('MOVIE_URL: ', movie_url)
            with open('db.txt', 'a') as f:
                f.write('%s
    ' % movie_url)
            # save(movie_url)
            p.submit(save, movie_url)
            print('%s下载任务已经提交' % movie_url)
    
    def save(movie_url):
        print('%s SAVE: %s' % (current_thread().getName(), movie_url))
        try:
            response = requests.get(movie_url, stream=False)
            if response.status_code == 200:
                m = hashlib.md5()
                m.update(('%s%s.mp4' % (movie_url, time.time())).encode('utf-8'))
                filename = m.hexdigest()
                with open(r'./movies/%s.mp4' % filename, 'wb') as f:
                    f.write(response.content)
                    f.flush()
        except Exception as e:
            print(e)
    
    def main():
        index_url = 'http://www.xiaohuar.com/list-3-{0}.html'
        for i in range(5):
            p.submit(get_page, index_url.format(i, )).add_done_callback(parse_index)
    
    if __name__ == '__main__':
        main()

       高级用法

        SSL Cert Verification(验证证书)

    '''
    很多网站都是 https,但是不用证书也可以访问,大多数情况都是可以携带也可以不携带证书
    知乎百度等都是可带可不带
    有硬性要求的,则必须带,比如对于定向的用户,拿到证书后才有权限访问某个特定网站
    '''
    
    # 如果是 ssl 请求,首先检验证书是否合法;不合法则报错,程序终止
    import requests
    response = requests.get('https://www.12306.cn')  
    
    
    # 改进1:
    import requests
    response = requests.get('https://www.12306.cn', verify=False)
    print(response.status_code)  # 不验证证书,报警告,返回200
    
    
    # 改进2:
    import requests
    from requests.packages import urllib3
    urllib3.disable_warnings()  # 关闭警告
    respone=requests.get('https://www.12306.cn',verify=False)
    print(respone.status_code)  # 200
    
    
    # 改进3:加上证书
    import requests
    respone=requests.get('https://www.12306.cn', cert=('/path/server.crt', '/path/key'))
    print(respone.status_code)

       使用代理

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

    # 代理设置:先发送请求给代理,然后由代理帮忙发送(封ip是常见的事情)
    import requests
    proxies={'http':'http://egon:123@localhost:9743', # 随机从代理池取出一个IP发送请求
             # 带用户名密码的代理,@符号前是用户名与密码
            'http':'http://localhost:9743',
            'https':'https://localhost:9743'}
    
    respone=requests.get('https://www.12306.cn', proxies=proxies)
    print(respone.status_code)
    
    
    # 支持socks代理,安装:pip install requests[socks]
    import requests
    proxies = {'http': 'socks5://user:pass@host:port',
               'https': 'socks5://user:pass@host:port'}
    
    respone=requests.get('https://www.12306.cn', proxies=proxies)
    print(respone.status_code)

       超时设置

    # 两种超时:float or tuple
    # timeout=0.1 代表接收数据的超时时间
    # timeout=(0.1, 0.2)   0.1代表链接超时  0.2代表接收数据的超时时间
    
    import requests
    respone=requests.get('https://www.baidu.com', timeout=0.0001)

      异常处理 

    import requests
    from requests.exceptions import * # 可以查看requests.exceptions 获取异常类型
    
    try:
        r = requests.get('http://www.baidu.com', timeout=0.00001)
    except ReadTimeout:
        print('===:')
    except ConnectionError:  # 网络不通
         print('-----')
    except Timeout:
         print('aaaaa')
    except RequestException:
        print('Error')

      上传文件

    import requests
    
    files = {'file': open('a.jpg', 'rb')}
    response = requests.post('http://httpbiin.org/post', files=files)
    print(respone.status_code)
  • 相关阅读:
    c# 异步和同步问题(转载)
    用Python作GIS之四:Tkinter基本界面的搭建
    Linux必知必会--vmstat
    Linux必知必会--awk
    Linux必知必会--sed
    Linux必知必会--grep
    Linux必知必会--curl
    康威定律
    移动端抓包合集
    MySQL重置自增id
  • 原文地址:https://www.cnblogs.com/pupy/p/11989587.html
Copyright © 2020-2023  润新知