初识爬虫以及requests模块

摘要

一直都想学习一下python爬虫的相关知识,但是苦于一直没有时间。因此,非常感谢这次能够路飞学院学习到爬虫知识的机会。

  • 不会web能不能做爬虫? 不能
  • 写爬虫的时候经历的阶段
    • 找不到入口
    • 反复试,找到入口
  • 必备知识
    • 爬虫本质,通过代码伪造浏览器发送请求
    • http请求伪造的像不像
      • 请求头
        • user-agent:用户使用什么设备访问
        • cookie:在用户浏览器上保存的标记
      • 请求体
        • get数据
        • post数据
    • 分析http请求
      • chrome

什么是爬虫

网络爬虫(又被称为网页蜘蛛,网络机器人,在FOAF社区中间,更经常的称为网页追逐者),是一种按照一定的规则,自动地抓取万维网信息的程序或者脚本。另外一些不常使用的名字还有蚂蚁、自动索引、模拟程序或者蠕虫。

  • 通过编写程序,根据url获取网站信息
  • 伪造浏览器想某个地址发送http请求,获取返回的字符串

Requests

Python标准库中提供了:urllib、urllib2、httplib等模块以供Http请求,但是,使用起来非常不方便。

Requests 是使用 Apache2 Licensed 许可证的,基于Python开发的HTTP库,其在Python内置模块的基础上进行了高度的封装,从而使得Pythoner进行网络请求时,变得美好了许多,使用Requests可以轻而易举的完成浏览器可有的任何操作。

常用方法

GET请求

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 无参数
import requests
ret = requests.get(url="http://c.isme.pub")
print(ret.url)
print(ret.text)
# 有参数
import requests
params = {'key1': 'value1', 'key2': 'value2'}
ret = requests.get(url="http://c.isme.pub", params= params)
print(ret.url)
print(ret.text)

POST请求

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 基本POST实例
import requests
data = {'key1': 'value1', 'key2': 'value2'}
ret = requests.post(url="http://c.isme.pub", data=data)
print(ret.text)
# 发送请求头和数据实例
import requests
import json
url = "http://c.isme.pub"
data = {'some': 'data'}
headers = {'content-type': 'application/json'}
ret = requests.post(url = url, data=json.dumps(payload), headers=headers)
print(ret.text)
print(ret.cookies)

其他请求

1
2
3
4
5
6
7
8
9
10
requests.get(url, params=None, **kwargs)
requests.post(url, data=None, json=None, **kwargs)
requests.put(url, data=None, **kwargs)
requests.head(url, **kwargs)
requests.delete(url, **kwargs)
requests.patch(url, data=None, **kwargs)
requests.options(url, **kwargs)
# 以上方法均是在此方法的基础上构建
requests.request(method, url, **kwargs)

常用参数

  • method: 向url发送http请求的方法
    • requests.get requests.post get 和 post的本质就是method
    • post,get,delete, put, head, patch, options
  • url: 访问的url
  • params: get请求时传递的参数,post的时候也可以使用
    • params = {k1:vi}
  • data: post请求时传递的请求体
    • 浏览器显示的form data
    • data=json.dumps() == json
    • data = {k1:v1,k2:v2} or ‘k1=v1&k2=v2’
  • json: 请求时发送的json数据(json.dumps)
    • 浏览器显示的 request payload
    • 请求头中设置content-type: application/json
  • headers: 请求头
  • cookies: 请求时使用的cookies
  • proxies: 代理
1
2
3
4
5
6
proxies = {
"http": "192.168.1.1:80",
"http": "192.168.1.2:8080",
"https": "172.16.1.4:8829",
"http://10.20.1.128": "http://10.0.0.1:5332"
}
  • files: 上传文件
    • 可以传递字典或者元组
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
file_dict = {
'f1': open('readme','rb')
}
url = 'http://c.isme.pub'
requests.request('method'='POST',
url = url,
files = file_dict)
# 定制发送文件的文件名
file_dict = {
'f1': ('text.txt', open('readme','rb'))
}
file_dict = {
'f1': ('text.txt', 'xxxxxxxxxxxxxxaddsad')
}
## 带着文件的请求头
file_dict = {
'f1': ('text.txt', 'xxxxxxxxxxxxxxaddsad','application/text',{'k1':'0'})
}
  • auth: 基本http认证(Basic/Digest/Custom)
1
2
3
4
5
6
from requests.auth import HTTPBasicAuth, HTTPDigestAuth
ret = requests.get(
url = "http://c.isme.pub",
auth = HTTPBasicAuth('user','passwd')
)
  • timeout 超时时间
  • allow_redirects: 默认True 是否允许重定向
  • stream: 下载大文件时
1
2
3
4
5
6
7
ret = requests(url=url, stream=True)
for i in r.iter_content():
print(i)
from contextlib import closong
with closing(requests.get(url=url,stream=True)) as r:
for i in r.iter_content():
print(i)
  • cert: 证书(一般自己创建的证书时使用)
  • verify: 使用自己创建证书的时候确认是否继续访问
  • ret = request.Session() 用来保存客户端历史访问信息
    • ret.get(),ret.post() # 会自动携带cookie信息

实例

登录汽车之家并获取新闻信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
import requests
from bs4 import BeautifulSoup
# 新闻页面
ret = requests.get(url='https://www.autohome.com.cn/news/')
# 检测是什么编码
#print(ret.apparent_encoding)
# 设置编码
#ret.encoding='gbk'
ret.encoding = ret.apparent_encoding
#print(ret.content)
#print(ret.text)
# 解析,获取想要的内容 'html.parser'是解析器,lxml更快
soup = BeautifulSoup(ret.text,'html.parser')
div = soup.find(name='div', id='auto-channel-lazyload-article')
li_list = div.find_all(name='li')
for li in li_list:
h3 = li.find(name='h3')
if not h3:
continue
a = li.find(name='a')
#print(a.attrs["href"])
print("="*20)
print(h3.text)
print(a.get('href'))
p = li.find(name='p')
print(p.text)
# 获取图片
img = li.find(name='img')
# bs4的其他使用方式
# img = li.find(name='img',id='xxx',_class='asd')
# img = li.find(name='img',attrs={'id':'xxx','class':'asd'})
src = img.get('src')
file_name = src.rsplit("__", maxsplit=1)[1]
ret_img = requests.get(url="https:" + src)
with open(file_name,'wb') as f:
f.write(ret_img.content)

自动登录抽屉并点赞

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import requests
from bs4 import BeautifulSoup
headers = {
"User-agent" : 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36'
}
data = {
'phone':'8617600806797',
'password':"xxx",
'oneMonth':'1'
}
# 第一次访问获取未授权的cookie
r0 = requests.get(url='https://dig.chouti.com/', headers = headers)
r0_cookie = r0.cookies.get_dict()
# 发送用户名密码认证
ret = requests.post(url='https://dig.chouti.com/login',data= data, headers = headers,cookies = r0_cookie)
print(ret.text)
index = requests.get(url='https://dig.chouti.com/', headers = headers)
soup = BeautifulSoup(index.text, 'html.parser')
div = soup.find(name='div',id='content-list')
items = div.find_all(attrs={'class':'item'})
for item in items:
tag = item.find(name='div',attrs={'class':'part2'})
if not tag:
continue
nid = tag.get('share-linkid')
print(nid)
r1 = requests.post(url='https://dig.chouti.com/link/vote?linksId=%s' %nid,headers = headers, cookies=r0_cookie)
print(r1.text)

grequests

通过gevent与requests封装而成的异步HTTP请求,相当于requests的异步版本。

安装

1
pip install grequests

简单实用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import grequests
urls = [
'http://www.heroku.com',
'http://python-tablib.org',
'http://httpbin.org',
'http://python-requests.org',
'http://fakedomain/',
'http://kennethreitz.com'
]
rs = (grequests.get(u) for u in urls)
ret = grequests.map(rs)
print(ret)
def exception_handler(request, exception):
print "Request failed"
ret = grequests.map(rs, exception_handler=exception_handler)
print(ret)

参数

1
def grequests.map(requests, stream=False, size=None, exception_handler=None, gtimeout=None)
  • size: 协程的并发数
  • exception_handler: 捕获异常的处理方法
  • gtimeout: 整体请求的超时时间

由于底层是requests,因此requests的其他参数依然支持

事件钩子

1
2
3
4
5
6
7
8
9
10
11
12
def print_url(r, *args, **kwargs):
print(r.url)
url = "http://www.baidu.com"
# 1.
res = requests.get(url, hooks={"response":print_url})
# 2.
tasks = []
req = grequests.get(url, callback=print_url)
tasks.append(req)
res = grequests.map(tasks)

实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
import grequests
import time
import requests
urls = [
'https://docs.python.org/2.7/library/index.html',
'https://docs.python.org/2.7/library/dl.html',
'http://www.iciba.com/partial',
'http://2489843.blog.51cto.com/2479843/1407808',
'http://blog.csdn.net/woshiaotian/article/details/61027814',
'https://docs.python.org/2.7/library/unix.html',
'http://2489843.blog.51cto.com/2479843/1386820',
'http://www.bazhuayu.com/tutorial/extract_loop_url.aspx?t=0',
]
def method1():
t1 = time.time()
for url in urls:
res = requests.get(url)
t2 = time.time()
print('method1', t2 - t1)
def method2():
tasks = [grequests.get(u) for u in urls]
t1 = time.time()
res = grequests.map(tasks, size=3)
t2 = time.time()
print('method2', t2 - t1)
def method3():
tasks = [grequests.get(u) for u in urls]
t1 = time.time()
res = grequests.map(tasks, size=6)
t2 = time.time()
print('method3', t2 - t1)
if __name__ == '__main__':
method1()
method2()
method3()