requests
爬虫介绍
反爬机制
    门户网站,可以通过制定相应的策略或者技术手段,防止爬虫程序进行网站数据的爬取。
反反爬策略
    爬虫程序可以通过制定相关的策略或者技术手段,破解门户网站中具备的反爬机制,从而可以获取门户网站中相关的数据。
robots.txt协议:百度蜘蛛
    君子协议。规定了网站中哪些数据可以被爬虫爬取哪些数据不可以被爬取。
浏览器工具的使用(重点)
Chrome是一款非常优秀的浏览器. 不仅仅体现在用户使用上. 对于我们开发人员而言也是非常非常好用的. 
对于一名爬虫工程师而言. 浏览器是最能直观的看到网页情况以及网页加载内容的地方. 我们可以按下F12来查看一些普通用户很少能使用到的工具. 
其中, 最重要的Elements, Console, Sources, Network. 
# 注意
1. 页面源代码是执行js脚本以及用户操作之前的服务器返回给我们最原始的内容
2. Elements中看到的内容是js脚本以及用户操作之后的当时的页面显示效果. 
    在Elements中我们可以使用左上角的小箭头.可以直观的看到浏览器中每一块位置对应的当前html状况. 
3.Console是用来查看程序员留下的一些打印内容, 以及日志内容的. 我们可以在这里输入一些js代码自动执行.
4.Source, 这里能看到该网页打开时加载的所有内容. 包括页面源代码. 脚本. 样式, 图片等等全部内容. 
5.Network, 我们一般习惯称呼它为抓包工具. 在这里, 我们能看到当前网页加载的所有网路网络请求, 以及请求的详细内容. 这一点对我们爬虫来说至关重要.
HTTP协议
协议: 就是两个计算机之间为了能够流畅的进行沟通而设置的一个君子协定. 常见的协议有TCP/IP. SOAP协议, HTTP协议, SMTP协议等等.....
HTTP协议, Hyper Text Transfer Protocol(超文本传输协议)的缩写,是用于从万维网(WWW:World Wide Web )服务器传输超文本到本地浏览器的传送协议.就是浏览器和服务器之间的数据交互遵守的就是HTTP协议. 
HTTP协议把一条消息分为三大块内容. 无论是请求还是响应都是三块内容
请求
请求行 -> 请求方式(get/post) 请求url地址 协议
请求头 -> 放一些服务器要使用的附加信息
请求体 -> 一般放一些请求参数
请求头中最常见的一些重要内容(爬虫需要):
1. User-Agent : 请求载体的身份标识(用啥发送的请求)
2. Referer: 防盗链(这次请求是从哪个页面来的?  反爬会用到)
3. cookie: 本地字符串数据信息(用户登录信息, 反爬的token)
响应
状态行 -> 协议 状态码 
响应头 -> 放一些客户端要使用的一些附加信息
响应体 -> 服务器返回的真正客户端要用的内容(HTML,json)等
响应头中一些重要的内容: 
1. cookie: 本地字符串数据信息(用户登录信息, 反爬的token)
2. 各种神奇的莫名其妙的字符串(这个需要经验了, 一般都是token字样, 防止各种攻击和反爬)
我们写爬虫的时候要格外注意请求头和响应头. 这两个地方一般都隐含着一些比较重要的内容.
注意:你的浏览器实际上把HTTP的请求和响应的内容进行重组了.显示成我们更容易阅读的效果.
requests 简介
介绍:
使用requests可以模拟浏览器的请求,比起之前用到的urllib,requests模块的api更加便捷(本质就是封装了urllib3)
注意:
requests库发送请求将网页内容下载下来以后,并不会执行js代码,这需要我们自己分析目标站点然后发起新的request请求
安装:
pip3 install requests
1. requests.get()  发送get请求,  请求参数可以直接放在`url`的`?`后面, 也可以放在字典里, 传递给`params`. 
2. requests.post() 发送post请求, 请求参数要放在`字典`里, 传递给`data`
3. resp.text  接收`文本`, 本质就是把`resp.content`进行`decode()`的结果.
4. resp.json() 接收`resp.json()`
5. resp.content 接收`字节`
一 基于GET请求
注意:GET请求:Query String Parameters  => url
1、基本请求
# 抓取搜狗搜索内容
kw = input("请输入你要搜索的内容:")
response = requests.get(f"https://www.sogou.com/web?query={kw}")  # 发送get请求
# print(response.text)  # 直接拿结果(文本)
2、带参数的GET请求->headers
# 爬取豆瓣
import requests
url = "https://movie.douban.com/j/chart/top_list?type=13&interval_id=100%3A90&action=&start=0&limit=20"
headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.88 Safari/537.36"
}
resp = requests.get(url, headers=headers)
# print(resp.text)
dic = resp.json()
print(dic)
3.带参数的GET请求->params
# 爬取豆瓣
import requests
url = "https://movie.douban.com/j/chart/top_list"
headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.88 Safari/537.36"
}
param = {
    "type": "13",
    "interval_id": "100:90",
    "action": "",
    "start": "0",
    "limit": "20",
}
resp = requests.get(url, params=param, headers=headers)
dic = resp.json()
print(dic)
print(resp.request.url)
4、带参数的GET请求->cookies
#登录github,然后从浏览器中获取cookies,以后就可以直接拿着cookie登录了,无需输入用户名密码
import requests
Cookies={   'user_session':'wGMHFJKgDcmRIVvcA14_Wrt_3xaUyJNsBnPbYzEL6L0bHcfc',
}
response=requests.get('https://github.com/settings/emails',
             cookies=Cookies) #github对请求头没有什么限制,我们无需定制user-agent,对于其他网站可能还需要定制
print('2101314568@qq.com' in response.text) #True
二 基于POST请求
注意:POST请求:Form Data    => data
1、基于post请求
# 爬取百度翻译单词
import requests
url = 'https://fanyi.baidu.com/sug'
# 参数
data = {
    "kw": "jay"
}
resp = requests.post(url, data=data)
dic = resp.json()
print(dic)
三 响应Response
1、response属性
import requests
respone=requests.get('http://www.jianshu.com')
# respone属性
print(respone.text)
print(respone.content)
print(respone.status_code)
print(respone.headers)
print(respone.cookies)
print(respone.cookies.get_dict())
print(respone.cookies.items())
print(respone.url)
print(respone.history)
print(respone.encoding)
#关闭:response.close()
from contextlib import closing
with closing(requests.get('xxx',stream=True)) as response:
    for line in response.iter_content():
    pass
2、编码问题
#编码问题
import requests
response=requests.get('http://www.autohome.com/news')
# response.encoding='gbk' #汽车之家网站返回的页面内容为gb2312编码的,而requests的默认编码为ISO-8859-1,如果不设置成gbk则中文乱码
print(response.text)
3、获取二进制数据
# 下载一个图片
import requests
url = "https://desk-fd.zol-img.com.cn/t_s960x600c5/g5/M00/00/07/ChMkJl3qNKaIDNA2AARqqK0FxbEAAvnJAJbLQMABGrA592.jpg"
resp = requests.get(url)
# print(resp.text)  # 你访问的url并不是一个文本
content = resp.content  # 拿到的是字节
# 保存图片
with open("哈哈.jpg", mode="wb") as f:
    f.write(content)
4、stream参数
一点一点的取,比如下载视频时,如果视频100G,用response.content然后一下子写到文件中是不合理的
import requests  
  
url = 'https://gss3.baidu.com/6LZ0ej3k1Qd3ote6lo7D0j9wehsv/tieba-smallvideo-transcode/1767502_56ec685f9c7ec542eeaf6eac93a65dc7_6fe25cd1347c_3.mp4'  
#stream=True 参数是在 requests.get() 调用中传递的,它告诉 requests 库不要立即下载整个响应内容,而是允许你通过 iter_content() 方法逐块地下载。这对于处理大文件或需要节省内存的情况非常有用。  
response = requests.get(url, stream=True)  
  
# 确保响应是成功的  
if response.status_code == 200:  
    with open('b.mp4', 'wb') as f:  
        for chunk in response.iter_content(chunk_size=8192):  # 8192 通常是块大小的默认值  
            if chunk:  # 确保chunk不是空的  
                f.write(chunk)  
    print("File downloaded successfully.")  
else:  
    print(f"Error occurred: {response.status_code}")
5.解析json
# 爬取豆瓣
import requests
url = "https://movie.douban.com/j/chart/top_list?type=13&interval_id=100%3A90&action=&start=0&limit=20"
headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.82 Safari/537.36"
}
resp = requests.get(url, headers=headers)
# print(resp.text)  # {} [] 单纯, 拿文本. html, json  => 字符串
lst = resp.json()  # 获取json数据 json => 字典
print(lst)
6.重定向
import requests
import re
#第一次请求
r1=requests.get('https://github.com/login')
r1_cookie=r1.cookies.get_dict() #拿到初始cookie(未被授权)
authenticity_token=re.findall(r'name="authenticity_token".*?value="(.*?)"',r1.text)[0] #从页面中拿到CSRF TOKEN
#第二次请求:带着初始cookie和TOKEN发送POST请求给登录页面,带上账号密码
data={
    'commit':'Sign in',
    'utf8':'✓',
    'authenticity_token':authenticity_token,
    'login':'317828332@qq.com',
    'password':'alex3714'
}
#测试一:没有指定allow_redirects=False,则响应头中出现Location就跳转到新页面,r2代表新页面的response
r2=requests.post('https://github.com/session',
             data=data,
             cookies=r1_cookie
             )
print(r2.status_code) #200
print(r2.url) #看到的是跳转后的页面
print(r2.history) #看到的是跳转前的response
print(r2.history[0].text) #看到的是跳转前的response.text
#测试二:指定allow_redirects=False,则响应头中即便出现Location也不会跳转到新页面,r2代表的仍然是老页面的response
r2=requests.post('https://github.com/session',
             data=data,
             cookies=r1_cookie,
             allow_redirects=False
             )
print(r2.status_code) #302
print(r2.url) #看到的是跳转前的页面https://github.com/session
print(r2.history) #[]
四 高级使用方法
1、SSL Cert Verification
#证书验证(大部分网站都是https)
import requests
respone=requests.get('https://www.12306.cn') #如果是ssl请求,首先检查证书是否合法,不合法则报错,程序终端
#改进1:去掉报错,但是会报警告
import requests
respone=requests.get('https://www.12306.cn',verify=False) #不验证证书,报警告,返回200
print(respone.status_code)
#改进2:去掉报错,并且去掉警报信息
import requests
from requests.packages import urllib3
urllib3.disable_warnings() #关闭警告
respone=requests.get('https://www.12306.cn',verify=False)
print(respone.status_code)
#改进3:加上证书
#很多网站都是https,但是不用证书也可以访问,大多数情况都是可以携带也可以不携带证书
#知乎\百度等都是可带可不带
#有硬性要求的,则必须带,比如对于定向的用户,拿到证书后才有权限访问某个特定网站
import requests
respone=requests.get('https://www.12306.cn',
                     cert=('/path/server.crt',
                           '/path/key'))
print(respone.status_code)
2、使用代理
#官网链接: http://docs.python-requests.org/en/master/user/advanced/#proxies
#代理设置:先发送请求给代理,然后由代理帮忙发送(封ip是常见的事情)
import requests
proxies={
    'http':'http://egon:123@localhost:9743',#带用户名密码的代理,@符号前是用户名与密码
    '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)
3、超时设置
#超时设置
#两种超时: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)
4、 认证设置
#官网链接:http://docs.python-requests.org/en/master/user/authentication/
#认证设置:登陆网站是,弹出一个框,要求你输入用户名密码(与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、异常处理
#异常处理
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')
6、上传文件
import requests
files={'file':open('a.jpg','rb')}
respone=requests.post('http://httpbin.org/post',files=files)
print(respone.status_code)

 
                
             
         浙公网安备 33010602011771号
浙公网安备 33010602011771号