【Python】网络请求与实战「get + post」

379 阅读10分钟

了解一下 urllib:

urllib 库 是 Python 内置的 HTTP 请求库。它包含4个模块:

  • request:最基本的 HTTP 请求模块,可以用来模拟发送请求。

  • error:异常处理模块,如果出现请求错误,可以捕获异常,然后进行重试或其他操作。

  • parse:工具模块,提供了许多 URL 处理方法,如拆分、解析、合并等。

  • robotparser:主要用于识别网站的 rebots.txt 文件,然后判断哪些网站可以爬,哪些网站不可以爬。

request模块:发起请求,用于常规的网络请求(不含中文参数时)

urllib.request 模块提供了最基本的构造 HTTP 请求的方法,利用它可以模拟浏览器的一个请求发起过程,同时它还带有处理 authenticaton (授权验证), redirections (重定向), cookies (浏览器Cookies)以及其它内容。

常用的方法:
urlopen("网址"/"请求对象"):

urlopen()函数:可以向网站发送一个请求并获取响应,urlopen()不支持重构User-Agent。

read():读取服务器响应的内容
字节流 = response.read()
字符串 = response.read().decode("utf-8")

代码实例:

import urllib.request
import ssl

ssl._create_default_https_context = ssl._create_unverified_context

url = 'https://www.baidu.com/'  # 目标url

header = {
    "User-Agent:": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36"
}

response = urllib.request.urlopen(url)  # 发起请求
# html = response.read()  # 获取字节流
html = response.read().decode('utf-8')  # 获取响应:获取字符串
print(html)

print(response.getcode())  # 返回 http 的响应码   200
print(response.geturl())   # 返回实际数据的 url    https://www.baidu.com/
Request("网址","请求头"):

代码实例:

import urllib.request
import ssl

ssl._create_default_https_context = ssl._create_unverified_context

"""利用 urlopen() 方法可以实现最基本的请求发起,
但这几个简单的参数并不足以构建一个完整的请求,
如果请求中需要加入 headers 等信息,
我们就可以利用更强大的 Request 类来构建一个请求。"""

url = 'https://www.douban.com/'
header = {
    "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36"
}

# 1、创建请求对象并构建User-Agent
req = urllib.request.Request(url, headers=header)

# 2、获取响应对象  urlopen
# Request,通过构造这个这个数据结构,
# 一方面我们可以将请求独立成一个对象,另一方面可配置参数更加丰富和灵活
response = urllib.request.urlopen(req)

# 3读取响应对象的内容  read().decode("utf-8")
html = response.read().decode("utf-8")
print(html)

parse()模块:发起请求,用于解决请求中含有中文的参数

常用方法:
urlencode(字典):
quote(字符串):

代码实例:

import urllib.request
# import urllib.parse
from urllib.parse import urlencode
import ssl

ssl._create_default_https_context = ssl._create_unverified_context

""" parse 使用场景:
网络模块在向一个携带一个中文字样的url发送请求就会出现问题
解决:把中文处理成%+十六进制的样式

常用方法:

1、urlencode(字典)
2、quote(字符串) (这个里面的参数是个字符串)
"""

url1 = "https://www.baidu.com/s?wd=%E6%9D%AD%E5%B7%9E"
url2 = "https://www.baidu.com/s?wd=杭州"
url3 = "https://www.baidu.com/s?wd=python"

"""
方式一:
urlencode
传入参数类型:字典
功能:将存入的字典参数编码为URL查询字符串,即转换成以key1=value1&key2=value2的形式
"""
url = urllib.request.urlopen(url1)
r = {'wd': '杭州'}
result = urllib.parse.urlencode(r)   # 对r进行解码
newUrl = 'https://www.baidu.com/s?' + result
print(newUrl)

"""方式二:
url 单个字符串编码用 quote() 函数
"""

r = '杭州'
result = urllib.parse.quote(r)
nUrl = 'https://www.baidu.com/s?wd=' + result
print(nUrl)

urllib 保存图片的实例:

import requests
from urllib import request
# from urllib.request import urlretrieve
import ssl

ssl._create_default_https_context = ssl._create_unverified_context

""" urllib方法-参数说明:
url:外部或者本地url
filename:指定了保存到本地的路径(如果未指定该参数,urllib会生成一个临时文件来保存数据);
reporthook:是一个回调函数,我们可以利用这个回调函数来显示当前的下载进度;
data:指post到服务器的数据。该方法返回一个包含两个元素的元组;
(filename,headers),filename表示保存到本地的路径,header表示服务器的响应头。
"""

url = 'https://img2.baidu.com/it/u=2269682918,827552144&fm=253&fmt=auto&app=138&f=JPEG?w=231&h=500'

request.urlretrieve(url=url, filename='img.png')

"""reuqest方法:
"""

url = 'https://imgpp.ztupic.com/u/3kBE2U0qv6/1658297127421_bcac4c6e.jpg?x-oss-process=image/crop,w_1024,h_1542/resize,h_812/quality,q_85/sharpen,100'
response = requests.get(url)
with open('img2.png', mode='wb') as f:
    f.write(response.content)

Requests模块

Requests 是用Python语言编写,基于 urllib,采用 Apache2 Licensed 开源协议的 HTTP 库。它比 urllib 更加方便,可以节约我们大量的工作,完全满足 HTTP 测试需求。Requests 的哲学是以 PEP 20 的习语为中心开发的,所以它比 urllib 更加 Pythoner。更重要的是它支持 Python3。

Requests 模块的安装:

1、在终端使用命令安装:

pip install requests

若出现下载超时,换源即可:

# 示例
pip install requests -i https://pypi.tuna.tsinghua.edu.cn/simple/
# 阿里云 http://mirrors.aliyun.com/pypi/simple/
# 豆瓣http://pypi.douban.com/simple/
# 清华大学 https://pypi.tuna.tsinghua.edu.cn/simple/ 【推荐】
# 中国科学技术大学 http://pypi.mirrors.ustc.edu.cn/simple/
# 华中科技大学http://pypi.hustunique.com/"""

2、在开发工具中安装(略)

Requests 模块的使用:

  • requests.get("网址")
  • request.post("网址")
  • put、delete等等method不常用

Requests 常用参数:

  • url 请求的:url 地址 接口文档标注的接口请求地址;
  • params:请求数据中的链接,常见的一个 get 请求,请求参数都是在 url 地址中;
  • data:请求数据,参数 表单的数据格式;
  • json:接口常见的数据请求格式;
  • headers:请求头信息,http 请求中,比如说编码方式等内容添加;
  • cookie:保存的用户登录信息,比如做一些充值功能,但是需要用户已经登录,需要 cookie 信息的请求信息传输;

Requests 响应内容:

  • r.encoding 获取当前的编码
  • r.encoding = 'utf-8' 设置编码
  • r.text 以encoding解析返回内容。字符串方式的响应体,会自动根据响应头部的字符编码进行解码。
  • r.cookies 返回cookie
  • r.headers 以字典对象存储服务器响应头,但是这个字典比较特殊,字典键不区分大小写,若键不存在则返回None
  • r.status_code 响应状态码
  • r.json() Requests中内置的JSON解码器,以json形式返回,前提返回的内容确保是json格式的,不然解析出错会抛异常
  • r.content 以字节形式(二进制)返回。字节方式的响应体,会自动为你解码 gzip 和 deflate 压缩。

Requests 中 get 请求之参数应用:

方法一:把参数添加到 url 中

注意:接口与参数之间用?链接,参数用 key=value 的形式表示,多个参数用&符号链接

import requests

url = 'https://www.sogou.com/web?query=%E6%B5%B7%E8%B4%BC%E7%8E%8B&_asf=www.sogou.com&_ast=&w=01015002&p=40040108&ie=utf8&from=index-nologin&s_from=index&oq=&ri=0&sourceid=sugg&suguuid=&sut=0&sst0=1678439364372&lkt=0%2C0%2C0&sugsuv=1666847250696567&sugtime=1678439364372'

headers = {
    "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36"
}

# 以encoding解析返回内容。字符串方式的响应体,会自动根据响应头部的字符编码进行解码。
response = requests.get(url, headers=headers).text
print(response)
方法二:把参数添加到 parmas 中

注意:params 的数据类型为字典数据,同样必须满足键值对

"""把参数添加到 params 中"""

url = 'https://www.sogou.com/web'
headers = {
    "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36"
}
parmas = {
    "query": "小米汽车",
    "_asf": "www.sogou.com",
    "_ast": "",
    "w": "01015002",
    "p": "40040108",
    "ie": "utf8",
    "from": "index-nologin",
    "s_from": "index",
    "oq": "",
    "ri": "0",
    "sourceid": "sugg",
    "suguuid": "",
    "sut": "1",
    "sst0": "1686904902668",
    "lkt": "0,0,0",
    "sugsuv": "1686887536189389",
    "sugtime": "1686904902668",
}
html = requests.get(url, headers=headers, params=parmas).text
print(html)

扩展:快速将headers中的参数匹配为字典数据

使用正则替换
1 ctrl+a 选中

2 (.*):\s(.*)$
  "$1":"$2",

3 regax 勾选 

4 replace all

Requests 中 post 请求:

post 请求的应用场景:
  1. 网页需要登录的情况下;
  2. 需要给网页传输内容的情况下。

其实用法大多数和get请求一样,只是需要加上data参数。

语法格式:

response = requests.post("http://www.baidu.com/", data = data,headers=headers)

下面以 360翻译为例:

Network 的请求头中请求方式为 post,就以post为准吧,浅浅的尝试了一下,用get也可以实现。

import json

import requests

headers = {
    "pro": "fanyi",
    "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36",
}

content = input('请输入你要翻译的内容:')
# url = f"https://fanyi.so.com/index/search?eng=0&validate=&ignore_trans=0&query={content}"
url = f"https://fanyi.so.com/index/search"
data = {
    # 'eng': '0',
    # 'validate': '',
    # 'ignore_trans': '0',
    'query': f'{content}'
}

# response = requests.post(url, headers=headers)

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

# response = requests.get(url, headers=headers, params=data)

# response = requests.get(url, headers=headers)

response.encoding = 'utf-8'
# data = response.json()   # 把返回响应的json字符串转换成字典
# print(data['data']['fanyi'])

data=response.text
print(data, type(data))
print(json.loads(data)['data']['fanyi'])   # json.loads:json字符串转字典,用于语句    json.dumps:字典转json,用于语句

Cookie 与 Session 实战:

在浏览网站的过程中,经常会遇到有些页面只有登录之后才可以访问。

在登录之后可以连续访问很多次网站,但是有时候过一段时间就需要重新登录。

还有一些网站,在打开浏览器时就自动登录了,而且在很长时间内都不会失效。

这里面涉及 Session 和 Cookie。

Cookie 是什么?

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

Session 是什么?

Session,通过在服务端记录的信息确定用户身份,这里的 session 指的是会话。其本义是指有始有终的一系列动作、消息。例如打电话时,从拿起电话拨号到挂断电话之间的一系列过程就可以称为一个 Session。

图解:

image.png

好处:

用户只需要输入一次账号密码,之后再访问网页时,只需要在 Headers 信息利用 Cookie 包含 Session_id,后台就可以根据 Session_id 来判断用户是否登录。

set_cookie:

当我们多次登录过,cookie 信息会一直保存在浏览器中:

image.png

我们先清除 cookie,刷新界面再重新登录:就会没有了。

image.png

Cookie与Session实战案例:

以12306购买车票为例:

import requests

# 当里面的日期已过期时,需要更改日期后再运行
url = "https://kyfw.12306.cn/otn/leftTicket/query?leftTicketDTO.train_date=2023-06-30&leftTicketDTO.from_station=SHH&leftTicketDTO.to_station=HZH&purpose_codes=ADULT"

headers = {
    "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36",
    "Cookie": "_uab_collina=168774234581620326415402; JSESSIONID=9FF7A1A0483A09EA54B5C17164E83B69; BIGipServerotn=1725497610.24610.0000; user_device_id=ff59cfcc74bb464898d31cd3106151a6; user_device_id_timestamp=1687742335950; BIGipServerpassport=954728714.50215.0000; guidesStatus=off; highContrastMode=defaltMode; cursorStatus=off; fo=undefined; route=495c805987d0f5c8c84b14f60212447d; _jc_save_fromStation=%u4E0A%u6D77%2CSHH; _jc_save_toStation=%u676D%u5DDE%2CHZH; _jc_save_fromDate=2023-06-26; _jc_save_toDate=2023-06-26; _jc_save_wfdc_flag=dc",
}
session = requests.session()
response = session.get(url, headers=headers)
response.encoding = 'utf-8'

# print(response)  # <Response [200]>
# print(type(response))  # <class 'requests.models.Response'>
# print(response.text)
data = response.json()  # 获取所有的数据
# print(data)

"""数据混乱,需要进行数据清洗,获取其中一部分的目标数据"""

targetData = data['data']['result']  # 所有列表信息,是个列表数据
# print(targetData, len(targetData))

# 每一个 i 代表一条列车的信息,使用循环,取出每一个列车的信息
for i in targetData:

    # 设置一个计数器,计算我们想要拿到的数据的下标
    count = 0

    # 数据看上去太乱,找规律,对其进行分割
    itemData = i.split('|')  # 以'|',对列表 数据进行分隔,返回的也是一个列表数据
    # print(itemData)    # 打印分隔后的所有列表数据

    for j in itemData:  # 每一个 j 代表每一条列车信息的每个数据
        # print(count, j)  # 获取列车中每个数据的下标值
        count += 1

        """
        count = 3时,代表了车次,即:车次数据的下标是3
        下标为32:商务座/特等座
        下标为31:代表一等座剩余车票数量
        下标为30:二等座/二等包座
        """

    if itemData[31] != '无' and itemData[31] != '':  # 一等座既不是没票,也不是候补的情况下,就是有票
        print("车次" + itemData[3] + "有票,一等座剩余:" + itemData[31])  # 所有一等座车次的余票
    else:
        print(itemData[3], "该车次的车票已售罄。")