01.爬虫入门之requests

一 爬虫入门之requests

(一) 爬虫基本原理

1) 百度是个大爬虫
2) 模拟浏览器发送http请求---(请求库)(频率,cookie,浏览器头。。js反扒,app逆向)(抓包工具)-----》从服务器取回数据-----》解析数据--(解析库)(反扒)----》入库(存储库,)
3) 爬虫协议:

img

(二) requests模块

0 介绍

0) urllib 内置库,发送http请求,比较难用,requests是基于这个库的写的
1) requests, 应用非常广泛的请求库
2) 安装:pip3 install requests
3) request-html库(request,bs4,lxml等二次封装)
# 重要的参数:
4) User-Agent:请求头中标志是什么客户端发送的请求
5) Referer:上次请求的地址

# GET请求
HTTP默认的请求方法就是GET
     * 没有请求体
     * 数据必须在1K之内!
     * GET请求数据会暴露在浏览器的地址栏中

GET请求常用的操作:
    1). 在浏览器的地址栏中直接给出URL,那么就一定是GET请求
    2). 点击页面上的超链接也一定是GET请求
    3). 提交表单时,表单默认使用GET请求,但可以设置为POST

# POST请求
(1). 数据不会出现在地址栏中
(2). 数据的大小没有上限
(3). 有请求体
(4). 请求体中如果存在中文,会使用URL编码!

# !!!requests.post()用法与requests.get()完全一致,特殊的是requests.post()有一个data参数,用来存放请求体数据

1 发送get请求

1 携带数据,携带头,携带cookie。。。
import requests
response=requests.get('http://dig.chouti.com/')
print(response.text)		# 文本内容,如下图
# print(response.content)	# 二进制内容 视频,图片  
# res.iter_content()  		# <generator object iter_slices at 0x000001819DD4B780>,
						  # 是一个二进制内容迭代器,每次迭代是一个字符

# 不携带任何参数的话,会因为模仿浏览器不够像而报错

无标题1

(1) 自己拼接GET参数
#在请求头内将自己伪装成浏览器,否则百度不会正常返回页面内容
import requests
header = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.75 Safari/537.36',
    }
response=requests.get('https://www.baidu.com/s?wd=python&pn=1', headers=header,)
print(response.text)

res1=response.text

url编码和解码

# url编码和解码: 如果因为中文和特殊字符的原因不方便看,可以使用编码来解决
from urllib.parse import urlencode,unquote
# wd='燕窝'

# 编码,得到字符串
# encode_res=urlencode({'k':wd},encoding='utf-8')
# print(encode_res)  # k=%E7%87%95%E7%AA%9D

# 解码,得到字符串
res=unquote('%E7%87%95%E7%AA%9D')
print(res)  # 燕窝
(2) params参数的使用
#上述操作可以用requests模块的一个params参数搞定,本质还是调用urlencode
from urllib.parse import urlencode
wd='egon老师'
pn=1

response=requests.get('https://www.baidu.com/s',
                      params={
                          'wd':wd,
                          'pn':pn
                      },
                      headers=header)
res2=response.text

#验证结果,打开a.html与b.html页面内容一样
with open('a.html','w',encoding='utf-8') as f:
    f.write(res1) 
with open('b.html', 'w', encoding='utf-8') as f:
    f.write(res2)
(3) 带参数的GET请求->headers
# 通常我们在发送请求时都需要带上请求头,请求头是将自身伪装成浏览器的关键,常见的有用的请求头如下
Host			# 
Referer 		# 大型网站通常都会根据该参数判断请求的来源
User-Agent 		# 客户端
Cookie 			# Cookie信息虽然包含在请求头里,但requests模块有单独的参数来处理他,
				# headers={}内就不要放它了
#添加headers(浏览器会识别请求头,不加可能会被拒绝访问,比如访问https://www.zhihu.com/explore)
import requests
response=requests.get('https://www.zhihu.com/explore')
print(response.status_code) # 403


#自己定制headers,模仿浏览器发送请求
headers={
    'User-Agent':'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.76 Mobile Safari/537.36',
}
respone=requests.get('https://www.zhihu.com/explore',
                     headers=headers)
print(respone.status_code) #200
(4) 带参数的GET请求->cookies
#登录github,然后从浏览器中获取cookies,以后就可以直接拿着cookie登录了,无需输入用户名密码
#用户名:egonlin 邮箱378533872@qq.com 密码lhf@123

import requests

Cookies={'user_session':'wGMHFJKgDcmRIVvcA14_Wrt_3xaUyJNsBnPbYzEL6L0bHcfc',
}

response=requests.get('https://github.com/settings/emails',
             cookies=Cookies) #github对请求头没有什么限制,我们无需定制user-agent,对于其他网站可能还需要定制

print('378533872@qq.com' in response.text) #True
(5) cookie携带的两种方式:
# cookie携带的两种方式:
	## 如果是字符串形式,就放到请求头中
   	## 如果是字典,就放在参数中cookies = 字典,需要将一个个 k:v;k:v; 形式的数据转换成字典,比较麻烦
    ## 如果是cookiejar对象,cookies = cookiejar对象 ##[cookiejar.CookieJar()]

2 发送post请求

1 携带数据,携带头,携带cookie
(1) 介绍
#GET请求
HTTP默认的请求方法就是GET
     * 没有请求体
     * 数据必须在1K之内!
     * GET请求数据会暴露在浏览器的地址栏中

GET请求常用的操作:
       1. 在浏览器的地址栏中直接给出URL,那么就一定是GET请求
       2. 点击页面上的超链接也一定是GET请求
       3. 提交表单时,表单默认使用GET请求,但可以设置为POST

#POST请求
    (1). 数据不会出现在地址栏中
    (2). 数据的大小没有上限
    (3). 有请求体
    (4). 请求体中如果存在中文,会使用URL编码!

#!!!requests.post()用法与requests.get()完全一致,特殊的是requests.post()有一个data参数,用来存放请求体数据
(2) post模拟浏览器登录
# 对于登录来说,应该输错用户名或密码然后分析抓包流程,否则输对了浏览器就跳转了,还分析个毛线
  1. 自动登录github–>自己处理cookies信息
'''
一 目标站点分析
    浏览器输入 https://github.com/login
    然后输入错误的账号密码,抓包
    发现登录行为是post提交到:https://github.com/session
    而且请求头包含cookie
    而且请求体包含:
        commit:Sign in
        utf8:✓
        authenticity_token:lbI8IJCwGslZS8qJPnof5e7ZkCoSoMn6jmDTsL1r/m06NLyIbw7vCrpwrFAPzHMep3Tmf/TSJVoXWrvDZaVwxQ==
        login:egonlin
        password:123



二 流程分析
    先GET:https://github.com/login拿到初始cookie与authenticity_token
    返回POST:https://github.com/session, 带上初始cookie,带上请求体(authenticity_token,用户名,密码等)
    最后拿到登录cookie

​```
ps:如果密码是密文形式,则可以先输错账号,输对密码,然后到浏览器中拿到加密后的密码,github的密码是明文
​```

'''

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',
    'authenticity_token':authenticity_token,
    'login':'317828332@qq.com',
    'password':'alex3714'
}
r2=requests.post('https://github.com/session',
             data=data,
             cookies=r1_cookie
             )

login_cookie=r2.cookies.get_dict()

#第三次请求:以后的登录,拿着login_cookie就可以,比如访问一些个人配置
r3=requests.get('https://github.com/settings/emails',
                cookies=login_cookie)

print('317828332@qq.com' in r3.text) #True
  1. requests.session()保存cookie信息
import requests
import re

session=requests.session()
#第一次请求
r1=session.get('https://github.com/login')
authenticity_token=re.findall(r'name="authenticity_token".*?value="(.*?)"',r1.text)[0] #从页面中拿到CSRF TOKEN

#第二次请求
data={
    'commit':'Sign in',
    'authenticity_token':authenticity_token,
    'login':'317828332@qq.com',
    'password':'alex3714'
}
r2=session.post('https://github.com/session',
             data=data,
             )

#第三次请求
r3=session.get('https://github.com/settings/emails')

print('317828332@qq.com' in r3.text) #True
(3) 补充:默认请求头与传参方式
# 没有指定请求头,默认的请求头:application/x-www-form-urlencoed
requests.post(url='xxxxxxxx',
              data={'xxx':'yyy'}) # 默认的请求头:application/x-www-form-urlencoed

# 如果我们自定义请求头是application/json,并且用data传值, 则服务端取不到值,需要在请求头中手动添加:'content-type':'application/json',或者直接使用json传值,默认就是json格式
requests.post(url='',
              data={'':1,},
              headers={
                  'content-type':'application/json'
              })

requests.post(url='',
              json={'':1,},
              ) #默认的请求头:application/json

3 高级用法

1) 使用代理,上传文件,超时设置
(1) 使用代理
import requests
# 免费代理(不稳定)
# 收费代理(稳定)
proxies={
    'HTTP':'117.95.200.239:9999',
}
respone=requests.get('https://www.12306.cn',
                     proxies=proxies)

print(respone.status_code)

# 写一个django,取出访问者的ip地址,使用requests,加代理模块访问

###### 高匿和透明 ######
# 高匿:服务端取不到真实的ip
# 透明:服务端可以取到真实的ip地址  请求头中:X-Forwarded-For   Meta

# 代理池:搞一堆代理,放到列表中,每次发请求,随机出一个(开源代理池)

小案例:django测试代理

  1. 服务端
def test(request):
    ip=request.META.get('REMOTE_ADDR')
    print(ip)
    return HttpResponse(ip)
  1. 本地测试
import requests
proxies={
    'http':'139.224.19.30:3128',
}
res=requests.get('http://101.133.225.166:8000/test/',proxies=proxies)
print(res.text)
(2) 了解:异常处理
# 异常处理,更细粒度,可以直接使用大的Exception,再去输出具体问题
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')
(3) 了解:上传文件
import requests
files={'file':open('a.jpg','rb')}
respone=requests.post('http://httpbin.org/post',files=files)
print(respone.status_code)
(4) 了解:超时设置
# 超时设置
# 两种超时: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)
(5) 了解: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:加上证书
#很多网站都是https,但是不用证书也可以访问,大多数情况都是可以携带也可以不携带证书
#知乎\百度等都是可带可不带
#有硬性要求的,则必须带,比如对于定向的用户,拿到证书后才有权限访问某个特定网站
import requests
respone=requests.get('https://www.12306.cn',
                     cert=('/path/server.crt',
                           '/path/key'))
print(respone.status_code)
(6) 了解:认证设置
#官网链接: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)

4 响应对象Response

(1) response属性
import requests
respone=requests.get('https://www.autohome.com.cn/shanghai/')
# respone属性
print(respone.text)  			# 文本内容
print(respone.content)  		# 二进制

# print(respone.status_code) 	# 状态码
# print(respone.headers)    	# 响应头
# print(type(respone.cookies))	# cookie对象  RequestsCookieJar

from requests.cookies import RequestsCookieJar
# print(respone.cookies.get_dict()) # cookie对象转成字典
# print(respone.cookies.items())


# print(respone.url)    		# 请求地址
# print(respone.history) 		# 当你访问一个网站,有30x,重定向之前的地址,!重定向才有值!
								# 如:[<Response [301]>]

# #关闭:response.close()
# from contextlib import closing
# with closing(requests.get('xxx',stream=True)) as response:
#     for line in response.iter_content():
#     pass
(2) 编码问题
# 编码问题,有的网站的内容或部分内容的编码为gb2312
import requests
response=requests.get('http://www.autohome.com.cn/shanghai')
# response.encoding='gbk' 	# 汽车之家网站返回的页面内容为gb2312编码的,而requests的默认编码为ISO-8859-1,如果不设置成gbk则中文乱码
print(response.text)
(3) 获取二进制数据
import requests

response=requests.get('https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1509868306530&di=712e4ef3ab258b36e9f4b48e85a81c9d&imgtype=0&src=http%3A%2F%2Fc.hiphotos.baidu.com%2Fimage%2Fpic%2Fitem%2F11385343fbf2b211e1fb58a1c08065380dd78e0c.jpg')

with open('a.jpg','wb') as f:
    f.write(response.content)
(4) 获取二进制流
#stream参数:一点一点的取,比如下载视频时,如果视频100G,用response.content然后一下子写到文件中是不合理的
import requests

response=requests.get('https://gss3.baidu.com/6LZ0ej3k1Qd3ote6lo7D0j9wehsv/tieba-smallvideo-transcode/1767502_56ec685f9c7ec542eeaf6eac93a65dc7_6fe25cd1347c_3.mp4',
                      stream=True)

with open('b.mp4','wb') as f:
    for line in response.iter_content():
        f.write(line)
(5) 解析json
#解析json
import requests
response=requests.get('http://httpbin.org/get')

import json
res1=json.loads(response.text) 	# 太麻烦

res2=response.json() 			# 直接获取json数据

print(res1 == res2) 			# True
(6) 了解:Redirection and History

官网解释

By default Requests will perform location redirection for all verbs except HEAD.

We can use the history property of the Response object to track redirection.

The Response.history list contains the Response objects that were created in order to complete the request. The list is sorted from the oldest to the most recent response.

For example, GitHub redirects all HTTP requests to HTTPS:

>>> r = requests.get('http://github.com')

>>> r.url
'https://github.com/'

>>> r.status_code
200

>>> r.history
[<Response [301]>]
If you're using GET, OPTIONS, POST, PUT, PATCH or DELETE, you can disable redirection handling with the allow_redirects parameter:

>>> r = requests.get('http://github.com', allow_redirects=False)

>>> r.status_code
301

>>> r.history
[]
If you're using HEAD, you can enable redirection as well:

>>> r = requests.head('http://github.com', allow_redirects=True)

>>> r.url
'https://github.com/'

>>> r.history
[<Response [301]>]

使用GitHub登录跳转例子验证

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) 			# []
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值