Python爬虫课--第二节 爬虫请求模块 urllib.request,urllib.parse,requests模块

1 urllib.request模块

1.1 版本

python2 :urllib2、urllib
python3 :把urllib和urllib2合并,urllib.request

1.2 常⽤的⽅法

urllib.request.urlopen(“⽹址”) 作⽤ :向⽹站发起⼀个请求并获取响应

import urllib.request
# response是响应对象
response = urllib.request.urlopen('https://www.duitang.com/')
# read()把相应对象里面的内容读取出来
print(response.read())
结果输出一系列字节流
  • encode() 字符串–> 转换为bytes数据类型
  • decode() bytes数据类型–> 转换为字符串
    字节流 = response.read()
    字符串 = response.read().decode(“utf-8”)
import urllib.request
# response是响应对象
response = urllib.request.urlopen('https://www.duitang.com/')
# read()把相应对象里面的内容读取出来
html = response.read().decode('utf-8')
print(type(html),html)
结果就转化为了网页源代码格式 字符串类型

urllib.request.Request"⽹址",headers=“字典”) 可以支持重构User-Agent;urlopen()不⽀持重构User-Agent

  • 对于有反爬的网页
import urllib.request

url = 'https://www.baidu.com/'

headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.25 Safari/537.36 Core/1.70.3775.400 QQBrowser/10.6.4208.400'
}

# 1.创建请求对象
req = urllib.request.Request(url,headers=headers)
# 2.获取响应对象
response = urllib.request.urlopen(req)
# 3.读取响应对象内容  read().decode('utf-8')
html = response.read().decode('utf-8')

print(html)
结果就可呈现
  • 使用流程
  1. 利用Request()方法构建请求对象
  2. 利用urlopen()方法去获取响应对象
  3. 利用响应对象中的read().decode(‘utf-8’) 读取响应对象内容

1.3 响应对象

read() 读取服务器响应的内容
getcode() 返回HTTP的响应码

import urllib.request

url = 'https://www.baidu.com/'

headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.25 Safari/537.36 Core/1.70.3775.400 QQBrowser/10.6.4208.400'
}

# 1.创建请求对象
req = urllib.request.Request(url,headers=headers)
# 2.获取响应对象
response = urllib.request.urlopen(req)
# 3.读取响应对象内容  read().decode('utf-8')
html = response.read().decode('utf-8')

# print(html)

print(response.getcode()) #返回状态码结果 200

print(response.geturl()) #返回实际数据的URL地址 https://www.baidu.com/

geturl() 返回实际数据的URL(防⽌重定向问题)

import urllib.request

url = 'https://www.baidu.com/'

headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.25 Safari/537.36 Core/1.70.3775.400 QQBrowser/10.6.4208.400'
}

# 1.创建请求对象
req = urllib.request.Request(url,headers=headers)
# 2.获取响应对象
response = urllib.request.urlopen(req)
# 3.读取响应对象内容  read().decode('utf-8')
html = response.read().decode('utf-8')

print(response.geturl()) #返回实际数据的URL地址 https://www.baidu.com/

2 urllib.parse模块

2.1 常⽤⽅法

urlencode(字典),可以实现手动的将汉字变为十六进制

# https://www.baidu.com/s?wd=%E6%B5%B7%E8%B4%BC%E7%8E%8B

import urllib.parse

name = {'wd':'海贼王'}

name = urllib.parse.urlencode(name)

print(name)
结果
wd=%E6%B5%B7%E8%B4%BC%E7%8E%8B
  • 练习一
# 请输入要搜索的内容,并把搜索结果,保存到当前目录 帅哥.html

import urllib.request
import urllib.parse

# https://www.baidu.com/s?wd=%E6%B5%B7%E8%B4%BC%E7%8E%8B

# 拼接url
baseurl = 'https://www.baidu.com/s?'

name = input('请输入要搜索的内容:')

# 进行urlencode()编码
wd = {'wd':name}

name = urllib.parse.urlencode(wd)

url = baseurl + name

# print(url)
headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.25 Safari/537.36 Core/1.70.3775.400 QQBrowser/10.6.4208.400','Cookie':'BAIDUID=0E1D7663D747715D94313EFB4E2C33AC:FG=1; BIDUPSID=0E1D7663D747715D94313EFB4E2C33AC; PSTM=1587718856; BD_UPN=1a314753; BDUSS=lna0k2Tm1aVmV1dGgzQmlqSGRORE1EbEJrVTZXNFJNTXJlVHB5eXRmQjJRRDFmSUFBQUFBJCQAAAAAAAAAAAEAAAB73m8ltPS09LXEuMK4wjEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHazFV92sxVfVT; MCITY=-%3A; BDUSS_BFESS=lna0k2Tm1aVmV1dGgzQmlqSGRORE1EbEJrVTZXNFJNTXJlVHB5eXRmQjJRRDFmSUFBQUFBJCQAAAAAAAAAAAEAAAB73m8ltPS09LXEuMK4wjEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHazFV92sxVfVT; BDRCVFR[sK1aAlma4-c]=mk3SLVN4HKm; delPer=0; BD_CK_SAM=1; PSINO=1; BDRCVFR[S_ukKV6dOkf]=mk3SLVN4HKm; BD_HOME=1; BDRCVFR[feWj1Vr5u3D]=I67x6TjHwwYf0; H_PS_645EC=1ca8wohXaH4gHIjrqDXVa0cDekSx3Kaem5kzoR%2BMTsGHRIld8yQe%2BpZqvbk; BDORZ=B490B5EBF6F3CD402E515D22BCDA1598; H_PS_PSSID=1421_32439_32532_32328_32348_32045_32270_32115_31322_22157'
}
# 创建请求对象
req = urllib.request.Request(url,headers=headers)

# 获取响应对象
res = urllib.request.urlopen(req)

# 读取响应对象内容
html = res.read().decode('utf-8')

# 写入文件
with open('结果.html','w',encoding='utf-8') as f:

    f.write(html)
结果
输出一个html文件

quote(字符串) (这个⾥⾯的参数是个字符串)

  • 百度贴吧练习一
# 需求:输入要爬取贴吧的名称,输入爬取的起始页和终止页,把每一页保存到本地
# 分析:1.找url的规律
# 第一页 https://tieba.baidu.com/f?kw=%E5%A6%B9%E5%AD%90&pn=0
# 第二页 https://tieba.baidu.com/f?kw=%E5%A6%B9%E5%AD%90&pn=50
# 第三页 https://tieba.baidu.com/f?kw=%E5%A6%B9%E5%AD%90&pn=100
# 第四页 https://tieba.baidu.com/f?kw=%E5%A6%B9%E5%AD%90&pn=(n-1)*50
# 页数规律 pn = (当前页数-1)*50
# 分析:2.获取网页内容
# 分析:3.获取数据
  • 使用User-Agent时候,为了不让百度知道是人是鬼在操作,引入random
import random
import urllib.request
import urllib.parse
# 随机获取一个ua,去百度上找常见的User-Agent大全.可以多放几个

headers_list = [{
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.25 Safari/537.36 Core/1.70.3775.400 QQBrowser/10.6.4208.400'
},{'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.835.163 Safari/535.1'}]

headers = random.choice(headers_list)

name = input('请输入贴吧名:')

start = int(input('请输入起始页:'))

end = int(input('请输入结束页:'))

# 对贴吧name进行编码
kw = {'kw':name}

kw = urllib.parse.urlencode(kw)

# 拼接url 发请求 获得响应 保存数据
# 不是一页,要循环
for i in range(start,end+1):

    # 拼接url
    pn = (i-1)*50
    baseurl = 'https://tieba.baidu.com/f?'

    url = baseurl + kw + '&pn=' + str(pn)

    # 发起请求
    req = urllib.request.Request(url,headers=headers)

    # 获得响应
    res = urllib.request.urlopen(req)

    # 读取
    html = res.read().decode('utf-8')

    # 写入文件
    filename = '第' + str(i) + '页.html'

    with open(filename,'w',encoding='utf-8') as f:

        print(f'正在爬取第{i}页')

        f.write(html)
结果 

Python爬虫课--第二节 爬虫请求模块 urllib.request,urllib.parse,requests模块_第1张图片

  • 练习二
# import random
import urllib.request
import urllib.parse

# 读取页面的逻辑封装
def readPage(url):

    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.25 Safari/537.36 Core/1.70.3775.400 QQBrowser/10.6.4208.400'
    }

    # 发起请求
    req = urllib.request.Request(url, headers=headers)

    # 获得响应
    res = urllib.request.urlopen(req)

    # 读取
    html = res.read().decode('utf-8')

    return html

# 写入文件
def writePage(filename,html):

    with open(filename, 'w', encoding='utf-8') as f:

        f.write(html)

# 主函数
def main():

    name = input('请输入贴吧名:')

    start = int(input('请输入起始页:'))

    end = int(input('请输入结束页:'))

    # 对贴吧name进行编码
    kw = {'kw': name}

    kw = urllib.parse.urlencode(kw)

    for i in range(start,end+1):

        # 拼接url
        pn = (i - 1) * 50
        baseurl = 'https://tieba.baidu.com/f?'

        url = baseurl + kw + '&pn=' + str(pn)

        html = readPage(url)

        filename = '第' + str(i) + '页.html'

        writePage(filename,html)

if __name__ == '__main__':

    main()

结果三个页面
请输入贴吧名:帅哥
请输入起始页:1
请输入结束页:3
  • 练习三 类对象实现
import urllib.request
import urllib.parse

class BaiduSpider:

    def __init__(self):

        #把常用的不变的放到init方法里面
        self.headers = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.25 Safari/537.36 Core/1.70.3775.400 QQBrowser/10.6.4208.400'
        }
        self.baseurl = 'https://tieba.baidu.com/f?'


    def readPage(self,url):

        # 发起请求
        req = urllib.request.Request(url, headers=self.headers)

        # 获得响应
        res = urllib.request.urlopen(req)

        # 读取
        html = res.read().decode('utf-8')

        return html

    def writePage(self,filename,html):

        with open(filename,'w',encoding='utf-8') as f:

            f.write(html)

    def main(self):

        name = input('请输入贴吧名:')

        start = int(input('请输入起始页:'))

        end = int(input('请输入结束页:'))

        # 对贴吧name进行编码
        kw = {'kw': name}

        kw = urllib.parse.urlencode(kw)

        for i in range(start, end + 1):
            # 拼接url
            pn = (i - 1) * 50

            url = self.baseurl + kw + '&pn=' + str(pn)

            html = self.readPage(url)

            filename = '第' + str(i) + '页.html'

            self.writePage(filename, html)


if __name__ == '__main__':

    # 如果要调用类对象中的main方法,
    #先需要实例化
    spider = BaiduSpider()

    spider.main()

3 请求⽅式

  • GET 特点 :查询参数在URL地址中显示

  • POST 在Request⽅法中添加data参数
    urllib.request.Request(url,data=data,headers=headers)
    data :表单数据以bytes类型提交,不能是str

  • 有道翻译练习

import urllib.request
import urllib.parse
import json

# 请输入你要翻译的内容

key = input('请输入要翻译的内容:')

# 把需要提交的form表单数据转换为bytes类型的数据  为什么就知道用form表单里的东西

data = {
    'i': key,

    'from': 'AUTO',
    'smartresult': 'dict',
    'client': 'fanyideskweb',
    'salt': '15980993133958',
    'sign': '8d249124b310aa8e7fa82f24049ff7b7',
    'lts': '1598099313395',
    'bv': '94d04da9bee8870ad9ad8714b54f2bea',
    'doctype': 'json',
    'version': '2.1',
    'keyfrom': 'fanyi.web',
    'action': 'FY_BY_REALTlME'

}

data = urllib.parse.urlencode(data)

# 把data转换为字节
data = bytes(data,'utf-8')

# 发请求获取响应 注意需要去掉_o
url = 'http://fanyi.youdao.com/translate?smartresult=dict&smartresult=rule'

headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.25 Safari/537.36 Core/1.70.3775.400 QQBrowser/10.6.4208.400'
    }

req = urllib.request.Request(url,data=data,headers=headers)
res = urllib.request.urlopen(req)
html = res.read().decode('utf-8')

# 这是一个json类型的字符串 {"type":"EN2ZH_CN","errorCode":0,"elapsedTime":1,"translateResult":[[{"src":"money","tgt":"钱"}]]}

# 将上述html的json类型的字符串变为字典dict
r_dict = json.loads(html)
r = r_dict['translateResult']  # 结果就是这个列表[[{"src":"money","tgt":"钱"}]]
result = r[0][0]['tgt']  # [{"src":"money","tgt":"钱"}]   -->  字典 {"src":"money","tgt":"钱"}
print(result)

请输入要翻译的内容:luck
运气

4 requests模块

4.1 安装

pip install requests
在开发⼯具中安装

4.2 request常⽤⽅法

requests.get(⽹址)

4.3 响应对象response的⽅法

response.text 返回unicode格式的数据(str)

print(response.text) # 返回的是str类型

response.content 返回字节流数据(⼆进制)

print(response.content) # 返回的是字节流

response.content.decode(‘utf-8’) ⼿动进⾏解码

print(response.content.decode('utf-8')) # ⼿动进⾏解码

response.url 返回url
response.encode() = ‘编码’
可以解决乱码问题

import requests

response = requests.get('http://www.qqbiaoqing.com/gaoxiao/')

# print(response.content.decode('utf-8'))

response.encoding = 'utf-8' # 如果没有这句,就会乱码
print(response.text)

4.4 requests模块发送 POST请求


import requests
import json

key = input('请输入翻译的内容')

# 把需要提交的form表单数据转换为bytes类型的数据  为什么就知道用form表单里的东西,因为输入的要素只出现在form表单里,所以去这找结果

data = {
    'i': key,

    'from': 'AUTO',
    'smartresult': 'dict',
    'client': 'fanyideskweb',
    'salt': '15980993133958',
    'sign': '8d249124b310aa8e7fa82f24049ff7b7',
    'lts': '1598099313395',
    'bv': '94d04da9bee8870ad9ad8714b54f2bea',
    'doctype': 'json',
    'version': '2.1',
    'keyfrom': 'fanyi.web',
    'action': 'FY_BY_REALTlME'

}

url = 'http://fanyi.youdao.com/translate?smartresult=dict&smartresult=rule'

headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.25 Safari/537.36 Core/1.70.3775.400 QQBrowser/10.6.4208.400'
    }

res = requests.post(url,data=data,headers=headers)

res.encoding = 'utf-8'

html = res.text
r_dict = json.loads(html)
result = r_dict['translateResult'][0][0]['tgt']

print(result)

请输入翻译的内容蜘蛛侠
spider-man

4.5 requests设置代理

使⽤requests添加代理只需要在请求⽅法中(get/post)传递proxies参数就可
以了
设置代理 http://www.httpbin.org/ip
代理⽹站
⻄刺免费代理IP:http://www.xicidaili.com/
快代理:http://www.kuaidaili.com/
代理云:http://www.dailiyun.com/

import requests

# 设置代理
proxy = {
    'http':'116.196.85.190:3128'
}
url = 'http://www.httpbin.org/ip'

res = requests.get(url,proxies=proxy)

print(res.text)

4.6 cookie

cookie :通过在客户端记录的信息确定⽤户身份,一旦确定之后,不用重复登录

HTTP是⼀种⽆连接协议,客户端和服务器交互仅仅限于 请求/响应过程,结束后断开,下⼀次请求时,服务器会认为是⼀个新的客户端,为了维护他们之间的连接,让服务器知道这是前⼀个⽤户发起的请求,必须在⼀个地⽅保存客户端信息。

  • 练习模拟登陆知乎

import requests

# resp = requests.get('https://www.baidu.com/')
#
# # print(resp.cookies.get_dict())

# 模拟登陆知乎
url = 'https://www2.zhihu.com/hot'

headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.25 Safari/537.36 Core/1.70.3775.400 QQBrowser/10.6.4208.400','cookie':'d_c0="AIBf6s8OKxGPTsCiOuJyoRVgNBjHstjKmcg=|1587727340"; _zap=6fc01f58-8fb3-4545-a781-417edf50e819; z_c0="2|1:0|10:1590034345|4:z_c0|92:Mi4xWG5HTEV3QUFBQUFBZ0ZfcXp3NHJFU1lBQUFCZ0FsVk5xVTJ6WHdBbm5kUGtSLXJQb2FMU1hENzN4S2FmbDVaTEln|b476020625a8a9eb38d3924904d14ed3f57ad5a55b29d104cf80d35e81bea1ee"; q_c1=c02ae3a1e68047a9965dc958423c0d2a|1597549527000|1590629112000; _xsrf=gBkpgEOmNKWElWsbjf040VnefHxTTo7h; SESSIONID=oEXxVPA7EVUX5OiYt43xIOXiy7UCkPTslsTf8EGneVW; JOID=U1sQBUPv6PqCRVtPRujzLV46uYVTzs3ar296ambFyd-iaHFuY874tNpOX0pL48DS0lAf9RdCtJESk6_0u8T_Xwg=; osd=UFoUBkPs6f6BRVhOQuvzLl8-uoVQz8nZr2x7bmXFyt6ma3FtYsr7tNlPW0lL4MHW0VAc9BNBtJITl6z0uMX7XAg=; tst=h; KLBRSID=ca494ee5d16b14b649673c122ff27291|1598232043|1598231842; tshl='
    }

resp = requests.get(url,headers=headers)

print(resp.text)

4.7 session

session :通过在服务端记录的信息确定⽤户身份 这⾥这个session就是⼀个指的是会话

  • 案例演示 首先对12306验证图片的获取–显得臃肿
import base64
# 需要删掉  data:image/jpg;base64,
url = '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'

img_data = base64.b64decode(url)

fn = open('code.png','wb')

fn.write(img_data)  # binascii.Error: Incorrect padding

fn.close()
  • 不臃肿的方式
# https://kyfw.12306.cn/passport/captcha/captcha-image64?login_site=E&module=login&rand=sjrand&1598271087088&callback=jQuery19102009473057696416_1598271069042&_=1598271069044

# https://kyfw.12306.cn/passport/captcha/captcha-image64?login_site=E&module=login&rand=sjrand&1598271171181&callback=jQuery19102009473057696416_1598271069042&_=1598271069045

# 一样的数据 https://kyfw.12306.cn/passport/captcha/captcha-image64?login_site=E&module=login&rand=sjrand

# 删掉64 后 得到12306的验证码图片 https://kyfw.12306.cn/passport/captcha/captcha-image?login_site=E&module=login&rand=sjrand
  • 拿到验证码图片,并验证成功–目前还没验证成功,可能是网速问题
# {result_message: "验证码校验成功", result_code: "4"}
# 思路 1. 请求目标url

# 2. 拿到12306的图片验证码

# 3. 点击正确的验证码图片

import requests

req = requests.session()

def login():

    # 2. 拿到12306的图片验证码,,用base64.b64decode(url)来对图片解码

    pic_response = req.get('https://kyfw.12306.cn/passport/captcha/captcha-image?login_site=E&module=login&rand=sjrand')
    # response.content是获取二进制bytes图片
    codeImage = pic_response.content
    fn = open('code2.png','wb')
    fn.write(codeImage)
    fn.close()


    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.25 Safari/537.36 Core/1.70.3775.400 QQBrowser/10.6.4208.400','Cookie':'_passport_session=98667d47f74a4c7d81305901dd36c9e01660; _passport_ct=62e61089c5a44c0085fcb801c9f58c32t0648; _jc_save_fromStation=%u5317%u4EAC%2CBJP; _jc_save_wfdc_flag=dc; RAIL_EXPIRATION=1598577388645; RAIL_DEVICEID=Z62kUSQ93InJ0ytt_VHqZ0HyI4LgmNJPNCy1YWOmEuLJJ6LnPtaqBp3KaJAlS7wPEQomC44E9qWi3XDmqvSla5-ciBeh66WoG9LP_kC2S876b9gFRBBP7P4MDq1q8HPk97o69ofSz6QtKyoaMyhrj7_-zjRk2SPw; _jc_save_fromDate=2020-08-25; _jc_save_toDate=2020-08-24; _jc_save_toStation=%u6C88%u9633%2CSYT; BIGipServerotn=317719050.38945.0000; route=c5c62a339e7744272a54643b3be5bf64; BIGipServerpool_passport=267190794.50215.0000'
    }

    codeStr = input('请输入验证码坐标:')

    data = {
        'answer': codeStr,   ## '58,53,266,45',
        'rand': 'sjrand',
        'login_site': 'E'
    }

    # 思路 1. 请求目标url 注意的是,现在请求方式是get,但是为了简单演示,采用post方式请求
    response = req.post('https://kyfw.12306.cn/passport/captcha/captcha-check',data=data,headers=headers)

    print(response.text)




    # 3. 点击正确的验证码图片

login()

  • 拿到车此信息
import requests

def query():


    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.25 Safari/537.36 Core/1.70.3775.400 QQBrowser/10.6.4208.400',
        'Cookie': '_uab_collina=159541602490128424256385; JSESSIONID=406B64ECCD5906E667DD5D42AD9045C7; _jc_save_fromStation=%u5317%u4EAC%2CBJP; _jc_save_wfdc_flag=dc; RAIL_EXPIRATION=1598577388645; RAIL_DEVICEID=Z62kUSQ93InJ0ytt_VHqZ0HyI4LgmNJPNCy1YWOmEuLJJ6LnPtaqBp3KaJAlS7wPEQomC44E9qWi3XDmqvSla5-ciBeh66WoG9LP_kC2S876b9gFRBBP7P4MDq1q8HPk97o69ofSz6QtKyoaMyhrj7_-zjRk2SPw; BIGipServerotn=317719050.38945.0000; route=c5c62a339e7744272a54643b3be5bf64; BIGipServerpool_passport=267190794.50215.0000; _jc_save_toStation=%u4E0A%u6D77%2CSHH; _jc_save_toDate=2020-08-25; _jc_save_fromDate=2020-09-01'
    }

    r = requests.get('https://kyfw.12306.cn/otn/leftTicket/query?leftTicketDTO.train_date=2020-09-01&leftTicketDTO.from_station=BJP&leftTicketDTO.to_station=SHH&purpose_codes=ADULT',headers=headers)

    print(r.content.decode('utf-8'))

query()

4.8 处理不信任的SSL证书

什么是SSL证书?
SSL证书是数字证书的⼀种,类似于驾驶证、护照和营业执照的电⼦副本。
因为配置在服务器上,也称为SSL服务器证书。SSL 证书就是遵守 SSL协
议,由受信任的数字证书颁发机构CA,在验证服务器身份后颁发,具有服务
器身份验证和数据传输加密功能

import requests
url = 'https://inv-veri.chinatax.gov.cn/'

resp = requests.get(url,verify = False) # verify = False加入之后就可以访问了

print(resp.text)

5 requests 模块源码分析

你可能感兴趣的:(python)