STAY HUNGRY , STAY FOOLISH.

求知若饥,虚心若愚。

       浏览:

Python之爬虫篇入门

上一篇《Python之基础篇》只是带大家入门python,能写python代码是基础中的基础,本篇文章主要讲解如何使用python去爬数据,在后续篇幅中会写python的其他应用场景,比如区块链、大数据分析、人工智能…。

说下本章需要介绍的有:

  • 爬虫
  • 爬虫的价值
  • 爬虫的分类及工作原理
  • 深度优先和广度优先算法
  • python3内置模块urllib
  • 第三方模块requests
  • 获取资源(福利)

1.爬虫

什么是爬虫?
简单理解就是确定爬取目标,通过爬数据的程序,为我所用
爬取目标包括网站、手机APP,需确定爬取的域名或平台;
数据包括文字(json)、图片(byte)、视频(byte)等,爬你所需;
程序包括cheerio(javascirpt)、scrapy(python)等,不限语言和框架;
为我所用包括数据库存储、硬件存储两种,持久化到哪,看具体需求。

引用别人的话:

在通往全栈程序员的道路上,爬虫是必不可少的一项技术。


2.爬虫的价值

做音乐推荐算法时,爬取网易音乐、豆瓣音乐用来做训练数据和标注集…
做自然语言处理时,爬取网易新闻的文章作为语料…
做垂直化电商时,爬取京东,天猫的数据,学习他们的数据结构设计…
偶尔设计师还要求做一些批量爬取dribbble图片的小工具…
做数据增长时,大量爬取竞品的商品,订单数据做竞品分析等等

这是别人所说的爬虫的价值,对于目前的我来说,爬虫的价值在于能自动获取自己需要的数据,不需要人为去维护。换句话说就是能实现数据生成自动化

以自己目前的想法举例,既找车场享健身两款app后,最近在做另一款app产品,叫享学习
该里面的内容会不断从其他网站或APP中产生,算是一个垂直化聚合类产品。如果能每天定时去爬别人的数据为我所用,那就太好了…

接下来系统的说下爬虫的价值:
1.数据服务
一般而言,支持数据采集的公司不是直接提供买卖数据的,而是提供服务,用户可根据其需求自定义爬哪些数据。不卖数据,卖服务,如八爪鱼集搜客神策数据等。

2.数据分析
有些爬数据的目的不是为我所用,而是根据数据去分析后面的价值。如金融证券股票等。

3.流量
有一个说法是,互联网上50%的流量都是爬虫创造的。这个说法虽然夸张了点,但也体现出了爬虫的无处不在。爬虫之所以无处不在,是因为爬虫可以为互联网企业带来收益。如微博粉丝网站访问量投票刷票等。

4.指数
具体说到的有百度指数阿里指数淘宝指数等。
百度指数是以百度海量网民行为数据为基础的数据分享平台。
阿里指数是以阿里电商数据为核心,面向媒体、市场研究员以及社会大众提供的社会化大数据展示平台;提供地域、行业等角度指数化的数据分析,作为市场及行业研究的参考、社会热点的洞察工具。
淘宝指数是通过它,用户可以窥探淘宝购物数据,了解淘宝购物趋势,而且产品不仅仅针对淘宝卖家,还包括淘宝买家及广大的第三方用户。

再说说爬虫的合法性,一般而言政府没有法律规定爬虫是违法的,也没有法律规定爬虫是合法的。
法律对爬虫这个没明确的条款说明,比如一家公司爬取另一家公司的数据后,会产生什么严重的后果,付怎样的责任,但也不完全说明,你能随便爬取一家公司的数据,爬虫算灰色产业
假如说一家公司让你爬取数据库(窃取商业机密)的话,那么责任在公司

那么,爬虫可以爬取所有东西吗?
不是。爬虫只能爬取用户能访问的数据
比如我是爱奇艺或腾讯视频的普通用户,我想通过爬虫爬取VIP视频且进行观看,那么这个爬虫是要付责任的!你就变黑客了…
如果我是爱奇艺或腾讯视频的VIP用户,我下载VIP视频来看是天经地义的,那么爬取按理说就不需要负责,因为你能访问VIP的数据,而普通用户不能。

爬虫价值谈完了,我们总结下爬虫的作用:
1.搜索引擎———百度、google、垂直领域搜索引擎
2.推荐引擎———今日头条、抖音
3.机器学习的数据样本
4.数据分析(如金融数据分析)、舆情分析


3.爬虫的分类及工作原理

爬虫分两大类:通用爬虫垂直化爬虫
通用爬虫,举例:百度、谷歌、360、sougou,只要是全局的搜索引擎,那就是通用爬虫,它的优势是开放性强、速度快,它的劣势是目标不明确,返回的内容基础上90%是用户不需要的。

垂直化爬虫,举例:前端开发博客,http://caibaojian.com。该博客
的所有数据来自码农头条(站长自己开发的爬虫),每日分享前端、移动开发、设计、资源和资讯等,为开发者提供动力。它的优势当然就是目标明确,爬取自己需要的数据,无关其他的数据,垂直化生产。

爬虫的工作原理:
1.确定你抓取目标的url是哪一个
2.使用python代码发送请求获取数据
3.解析获取到的精确数据
4.数据持久化


4.深度优先和广度优先算法(选看)

深度优先和广度优先算法在爬取一个整站上经常用到。
举例,有一个网站爬取url结构如下:

python-sf

伯乐在线
顶级域名是jobbole.com(A),
二级域名有python.jobbole.com(B)、web.jobbole.com(C),
详情页域名有python.jobbole.com/89328(D)、python.jobbole.com/89331(E)、web.jobbole.com/95432(F)、web.jobbole.com/95443(G)….

4.1.深度优先算法和实现

优先输出A、B、D、E、I、C、F、G、H(递归算法)

1
2
3
4
5
6
7
def depth_tree(tree_node):
if tree_node is not None:
print(tree_node.data)
if tree_node._left is not None:
return depth_tree(tree_node._left)
if tree_node._right is not None:
return depth_tree(tree_node._right)

缺点:栈容易溢出

4.2.广度优先算法和实现

优先输出A、B、C、D、E、F、G、H、I(队列算法)

1
2
3
4
5
6
7
8
9
10
11
12
13
def level_queue(root):
if root is None:
return
my_queue = []
node = root
my_queue.append(node)
while my_queue:
node = my_queue.pop(0)
print(node.elem)
if node.lchild is not None:
my_queue.append(node.lchild)
if node.rchild is not None:
my_queue.append(node.rchild)

5.python3内置模块urllib

上面都是简单讲解关于爬虫的基础和理论,并没有实战,从该节起,会详细讲解用python爬取页面。
python爬取页面可以使用内置模块urllib.request和第三方requests去处理请求,requests还是用内置模块封装的,因此我们先学习下使用urllib爬取百度页面。

5.1.get请求

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 引入urllib.request模块,用于发起请求
import urllib.request

# 封装get请求的方法
def load_get():
url = 'http://www.baidu.com/'
# 发起get请求,访问百度,获取响应
response = urllib.request.urlopen(url)
# 获取响应数据,换成utf-8格式的编码
data = response.read().decode('utf-8')
# 将响应数据存入baidu.html,文件写入IO流关闭
with open('baidu.html', 'w', encoding='utf-8') as f:
f.write(data)

# 执行方法
load_get()

5.2.post请求

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 引入urllib.request模块,用于发起请求
import urllib.request
# 全局取消证书验证
import ssl
ssl._create_default_https_context = ssl._create_unverified_context


# 封装post请求的方法
def load_post():
url = 'https://m.xjshen.cn/api/signature'
# 发起post请求
response = urllib.request.urlopen(url, data={})
print(response.read().decode('utf-8'))


# 执行方法
load_post()

小结一下:

发起get请求:urllib.request.urlopen(url)
发起post请求:urllib.request.urlopen(url=url, data={})
获取响应数据:response.read().decode(‘utf-8’)
取消ssl认证:ssl._create_default_https_context = ssl._create_unverified_context


5.3.get单个传参

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import urllib.request
import urllib.parse
import string


def load_baidu():
url = 'http://baidu.com/s?wd='
name = '享健身'
final_url = url + name
# 将包含汉字的网址进行转译
encode_new_url = urllib.parse.quote(final_url, safe=string.printable)
response = urllib.request.urlopen(encode_new_url)
data = response.read().decode('utf-8')
# python解释性语言;解析器只支持ascii码 0 - 127
# 不支持中文
with open('baidu-xjs.html', 'w', encoding='utf-8') as f:
f.write(data)


load_baidu()

小结一下:

get中文传参记得转码:urllib.parse.quote(final_url, safe=string.printable)


5.4.get多个传参

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import urllib.request
import urllib.parse
import string


def load_baidu():
url = 'http://baidu.com/s?wd='

params = {
'wd': '享健身',
'key': 'ww',
'key2': 'ww2'
}
# dict转string params
str_params = urllib.parse.urlencode(params)
final_url = url + str_params
# 将带有中文的url转译成计算机可识别的url
end_url = urllib.parse.quote(final_url, safe=string.printable)
response = urllib.request.urlopen(end_url)
data = response.read().decode()
print(data)


load_baidu()

小结一下:

get中请求参数是dict转str,urllib.parse.urlencode(params)


5.5.post传参

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 引入urllib.request模块,用于发起请求
import urllib.request
import urllib.parse
# 全局取消证书验证
import ssl
ssl._create_default_https_context = ssl._create_unverified_context


# 封装post请求的方法
def load_baidu():
url = 'https://m.xjshen.cn/api/signature'
# 发起post请求,获取响应
data = urllib.parse.urlencode({'a': '张三', 'b': '李四'})
data = data.encode('utf-8')
response = urllib.request.urlopen(url, data=data)
print(response.read())


# 执行方法
load_baidu()

小结一下:

post请求只支持byte类型,所以要进行再次编码


5.6.添加请求头信息

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
import urllib.request


def load_baidu():
url = 'http://baidu.com'
# 添加请求头的信息
header = {
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 '
'(KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36'
}
# 创建请求对象
request = urllib.request.Request(url, headers=header)
print('请求头------------')
print(request.headers)
# 开始请求(不在此处增加请求头信息,系统无提供)
response = urllib.request.urlopen(request)
# 响应头
print('响应头------------')
print(response.headers)
# 获取数据
data = response.read().decode('utf-8')
# 持久化
with open('baidu_header.html', 'w', encoding='utf-8') as f:
f.write(data)


load_baidu()

小结一下:

创建request:request = urllib.request.Request(url, headers=headers)
开始请求:urllib.request.urlopen(request)


5.7.http、https请求处理器handler

系统的urlopen不支持代理的添加,需自己创建对应的处理器handler。一个HTTP请求,就是一个HTPP Handler。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import urllib.request
# 全局取消证书验证
import ssl
ssl._create_default_https_context = ssl._create_unverified_context


def handler_openner():
# 系统的urlopen并没有添加代理的功能,需自定义
# 安全套阶层 ssl第三方的CA数字证书
# http 80端口 https 443端口
# urlopen为什么可以请求数据,使用了handler处理器
url = 'https://www.csdn.net'

# 创建自己的处理器
handler = urllib.request.HTTPSHandler()
# 创建自己的opener
opener = urllib.request.build_opener(handler)
# 用自己创建的opener方法请求数据
response = opener.open(url)
data = response.read().decode('utf-8')
print(data)


handler_openner()

小结一下:

response = urllib.request.urlopen(url)做了哪些事情?
1.创建handler
handler = urllib.request.HTTPSHandler()
2.创建opener
opener = urllib.request.build_opener(handler)
3.请求数据
response = openner.open(url)
基本的http/https请求所对应的处理器:HTTPHandler、HTTPSHandler


5.8.proxy代理请求处理器handler

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
import urllib.request
# 全局取消证书验证
import ssl
ssl._create_default_https_context = ssl._create_unverified_context


def create_proxy_handler():
url = 'https://www.csdn.net'
# 添加代理
proxy = {
# 免费的写法
'http': 'http://116.228.53.234:43414',
# 付费的写法
# 'http':'xiaoming':123@115.xxx
}
# 代理处理器
proxy_handler = urllib.request.ProxyHandler(proxy)
# 创建自己的opener
opener = urllib.request.build_opener(proxy_handler)
# 用自己创建的opener方法请求数据
response = opener.open(url)
data = response.read().decode('utf-8')
print(data)


create_proxy_handler()

小结一下:

想通过代理ip访问使用ProxyHandler请求处理器


5.9.内网认证请求处理器handle

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
import urllib.request


def auth_nei_wang():
# 1.用户名密码
user = 'admin'
pwd = '123456'
nei_url = 'http://192.168.1.0'

# 2.创建密码管理器
password_manager = urllib.request.HTTPPasswordMgrWithDefaultRealm()
password_manager.add_password(None, nei_url, user, pwd)

# 3.创建可以验证认证处理器
proxy_handler = urllib.request.HTTPBasicAuthHandler(password_manager)

# 4.通过处理器创建opener
opener = urllib.request.build_opener(proxy_handler)

# 4.open发送请求
response = opener.open(nei_url)
print(response.read())


auth_nei_wang()

小结一下:

有账号和密码认证的请求,记得有个HTTPPasswordMgrWithDefaultRealm请求对象和HTTPBasicAuthHandler请求处理器。


5.10.反爬虫手段:更改user-agent请求头

User Agent中文名为用户代理,简称UA,它是一个特殊字符串头,使得服务器能够识别客户使用的浏览器,隐藏爬虫的方式之一。

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 urllib.request
import random
# 全局取消证书验证
import ssl
ssl._create_default_https_context = ssl._create_unverified_context


def load_baidu():
url = 'http://baidu.com'
user_agent_list = [
'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.835.163 Safari/535.1',
'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:6.0) Gecko/20100101 Firefox/6.0',
'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534.50 (KHTML, like Gecko) Version/5.1 Safari/534.50',
'Opera/9.80 (Windows NT 6.1; U; zh-cn) Presto/2.9.168 Version/11.50',
'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0; .NET CLR 2.0.50727; SLCC2; '
'.NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; InfoPath.3; .NET4.0C; Tablet PC 2.0; .NET4.0E)',
'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/535.1 (KHTML, like Gecko) '
'Chrome/13.0.782.41 Safari/535.1 QQBrowser/6.9.11079.201',
'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0; SLCC2; .NET CLR 2.0.50727; '
'.NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; InfoPath.3; .NET4.0C; .NET4.0E)'
]
# 每次请求的浏览器都是不一样的
random_agent = random.choice(user_agent_list)
request = urllib.request.Request(url)
request.add_header('User-Agent', random_agent)

urllib.request.urlopen(request)
print(request.get_header('User-agent'))


load_baidu()

5.11 反爬虫手段:更改ip地址,免费版

更改user-agent请求头是防反爬虫的手段之一,还有另一个手段就是更改ip地址

IP代理:
免费的IP:时效性差,错误率高
付费的IP:时效性好,错误率低,贵花钱,也有失效不能用的

IP分类:
透明:对方知道我们真实的IP
匿名:对方不知道我们真实的IP,知道我们使用了代理
高匿:对方不知道我们真实的IP,不知道我们使用了代理

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
import urllib.request
# 全局取消证书验证
import ssl
ssl._create_default_https_context = ssl._create_unverified_context


def prxoy_user():
url = 'https://www.csdn.net'
proxy_list = [
{'http': 'http://116.228.53.234:43414'},
{'http': 'http://221.214.180.122:33190'},
{'http': 'http://183.16.28.8:8123'},
{'http': 'http://121.31.195.28:8123'},
{'http': 'http://125.46.0.62:53281'}
]
for proxy in proxy_list:
print(proxy)
# 利用遍历出来的ip创建处理器
proxy_handler = urllib.request.ProxyHandler(proxy)
# 创建opener
opener = urllib.request.build_opener(proxy_handler)
try:
# 请求数据
response = opener.open(url)
print(response)
except Exception as e:
print(e)


prxoy_user()

5.12 反爬虫手段:更改ip地址,收费版

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
41
import urllib.request

# 付费的代理发送
# 1.用户名密码
# 通过验证的处理器来发送


# 方式一
def money_proxy_use():
# 1.代理IP
money_proxy = {
'http': 'username:pwd@192.168.0.1'
}
# 2.代理的处理器
proxy_handler = urllib.request.ProxyHandler(money_proxy)

# 3.通过处理器创建opener
opener = urllib.request.build_opener(proxy_handler)

# 4.open发送请求
opener.open('http://baidu.com')


# 方式二
def money_proxy_pwd():
# 1.创建密码管理器,添加用户名和密码
password_manager = urllib.request.HTTPPasswordMgrWithDefaultRealm()
password_manager.add_password(None, '192.168.0.1', 'username', 'pwd')

# 2.创建可以验证代理ip的处理器
proxy_handler = urllib.request.ProxyBasicAuthHandler(password_manager)

# 3.通过处理器创建opener
opener = urllib.request.build_opener(proxy_handler)

# 4.open发送请求
response = opener.open('http://baidu.com')
print(response.read())


money_proxy_pwd()

小结一下:

有账号和密码认证的请求,记得有个HTTPPasswordMgrWithDefaultRealm请求对象和ProxyBasicAuthHandler请求处理器。


5.13.添加cookie,认证身份

方法一:手动添加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
import urllib.request
# 全局取消证书验证
import ssl
ssl._create_default_https_context = ssl._create_unverified_context


def get_myinfo():
url = 'https://www.yaozh.com/member/'
header = {
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/537.36 '
'(KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36',
'Cookie': 'WAF_SESSION_ID=7d88ae0fc48bffa022729657cf09807d; PHPSESSID=80jbqlbatqvvg337218d7sov26; _ga=GA1.2.217350335.1541433605; _gid=GA1.2.1435660402.1541433605; _gat=1; Hm_lvt_65968db3ac154c3089d7f9a4cbb98c94=1541433605; yaozh_userId=381740; UtzD_f52b_saltkey=V60kbZ7e; UtzD_f52b_lastvisit=1541430020; yaozh_uidhas=1; yaozh_mylogin=1541433623; WAF_SESSION_ID=7d88ae0fc48bffa022729657cf09807d; MEIQIA_VISIT_ID=1CZifOOl6L8nNQki92lcLzhcpRc; MEIQIA_EXTRA_TRACK_ID=1CZifMiG9Inp8b1B7UmGPdcLfxN; MEIQIA_VISIT_ID=1CZifOOl6L8nNQki92lcLzhcpRc; MEIQIA_EXTRA_TRACK_ID=1CZifMiG9Inp8b1B7UmGPdcLfxN; UtzD_f52b_ulastactivity=1511944816%7C0; UtzD_f52b_creditnotice=0D0D2D0D0D0D0D0D0D368675; UtzD_f52b_creditbase=0D1D432D0D0D0D0D0D0; UtzD_f52b_creditrule=%E6%AF%8F%E5%A4%A9%E7%99%BB%E5%BD%95; yaozh_logintime=1541433898; yaozh_user=381740%09xiaomaoera12; db_w_auth=368675%09xiaomaoera12; UtzD_f52b_lastact=1541433898%09uc.php%09; UtzD_f52b_auth=ba8avRnC9EkmA7Yn4wCL2SfIefXDEHZhLJoeJY02ZHZ2CflUuKqGbRLZ7z8%2BFYtmOlZIbUxrMA5omlvHzucBan4ERP8; Hm_lpvt_65968db3ac154c3089d7f9a4cbb98c94=1541433918'
}
request = urllib.request.Request(url, headers=header)
try:
response = urllib.request.urlopen(request, timeout=5)
data = response.read()
with open('yaozh.html', 'wb') as f:
f.write(data)
except Exception as e:
print(e)


get_myinfo()

方法二:根据业务,代码实现登录成功,获取到token后再去访问页面

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
41
42
43
import urllib.request
import ssl
from http import cookiejar
from urllib import parse
# 全局取消证书验证
ssl._create_default_https_context = ssl._create_unverified_context

# 1.代码登录
# 1.1 登录的网址
login_url = 'https://www.yaozh.com/login'
# 1.2 发生登录请求
login_form_data = {
'username': 'xiaomaoera12',
'pwd': 'lina081012',
'formhash': '36EBB186C4',
'backurl': 'https%3A%2F%2Fwww.yaozh.com%2F'
}
# 1.3 发送登录请求POST
cook_jar = cookiejar.CookieJar()
# 定义有添加cookie功能的处理器
cook_handler = urllib.request.HTTPCookieProcessor(cook_jar)
# 根据处理器生成opener
opener = urllib.request.build_opener(cook_handler)
# 带着参数发送post请求,添加请求头
headers = {
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/537.36 '
'(KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36',
}
# 参数将来需要转义转码;post请求的 data要求是bytes
login_str = parse.urlencode(login_form_data).encode('utf-8')
login_request = urllib.request.Request(login_url, headers=headers, data=login_str)
# 如果登录成功,cookiejar自动保存cookie
opener.open(login_request)


# 2.代码带着cookie去访问 个人中心
center_url = 'https://www.yaozh.com/member/'
center_request = urllib.request.Request(center_url, headers=headers)
response = opener.open(center_url)
# bytes --> str
data = response.read().decode('utf-8')
with open('yaozh.html', 'w') as f:
f.write(data)

小结一下:

通过HTTPCookieProcessor请求处理器携带cookie去连续请求


5.14.请求错误

常见的请求错误编码有,400,403,404,405,500,503。
常见的python请求错误如下:

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
# urllib.request 提示错误 HTTPError UrlError

# raise URLError(err)
# urllib.error.URLError: <urlopen error [Errno 8] nodename nor servname provided, or not known>

# raise URLError(err)
# urllib.error.URLError: <urlopen error [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:833)>

# raise HTTPError(req.full_url, code, msg, hdrs, fp)
# urllib.error.HTTPError: HTTP Error 404: Not Found

# raise ProxyError(e, request=request)
# requests.exceptions.ProxyError: HTTPConnectionPool(host='121.31.195.28', port=8123): Max retries exceeded
# with url: http://www.baidu.com/ (Caused by ProxyError('Cannot connect to proxy.',
# NewConnectionError('<urllib3.connection.HTTPConnection object at 0x109fd59e8>: Failed to establish a new connection:
# [Errno 61] Connection refused',)))


# raise SSLError(e, request=request)
# requests.exceptions.SSLError: HTTPSConnectionPool(host='test.xjshen.cn', port=443): Max retries exceeded with url: /
# (Caused by SSLError(CertificateError("hostname 'test.xjshen.cn' doesn't match either of 'blog.xjshen.cn',
# 'easy.xjshen.cn', 'image.xjshen.cn', 'm.xjshen.cn', 'xcx.xjshen.cn', 'xjshen.cn'",),))

import urllib.request
import ssl
# 全局取消证书验证
ssl._create_default_https_context = ssl._create_unverified_context

url = 'https://blog.csdn.net/u012814696/article/details/56479455d/fasd'
try:
response = urllib.request.urlopen(url)
except urllib.request.HTTPError as e:
print(e.code)
except urllib.request.URLError as e:
print(e)
except Exception as e:
print(e)

小结一下:

通过try…except…语句去抛异常

至此,有关python内置的urilib模块讲解完毕,这节讲解的知识点确实蛮多的,但都是为了下一步使用requests打下基础,当使用requests的时候,会发现这些复杂的操作已经帮你都封装好了,你只需要简单的调用其api即可。


6.第三方模块requests

requests

requests官网:http://www.python-requests.org
requests特点:简单易用url自动转译同时支持python2/python3

6.1.使用方法:安装第三方模块 requests

1
pip install requests

6.2.get请求

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 引入requests模块
import requests

# 封装get请求的方法
def load_get():
url = 'http://www.baidu.com/'
# 发起get请求,访问百度,获取响应
response = requests.get(url)
# content属性 返回的类型 是bytes
# 获取响应数据,换成utf-8格式的编码
data = response.content.decode('utf-8')
# 将响应数据存入baidu.html,文件写入IO流关闭
with open('baidu.html', 'w', encoding='utf-8') as f:
f.write(data)

# 执行方法
load_get()

6.3.post请求

1
2
3
4
5
6
7
8
9
10
11
12
13
# 引入requests模块,用于发起请求
import requests

# 封装post请求的方法
def load_post():
url = 'https://m.xjshen.cn/api/signature'
# 发起post请求
response = requests.post(url)
print(response.content.decode('utf-8'))


# 执行方法
load_post()

6.4.常见操作

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
import requests

class RequestSpider(object):
def __init__(self):
url = 'http://www.baidu.com'
headers = {
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/537.36 '
'(KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36',
}
self.response = requests.get(url, headers=headers)

def run(self):
data = self.response.content
# 1.获取请求头
request_headers = self.response.request.headers
# 2.获取响应头
response_headers = self.response.headers
# 3.响应状态码
code = self.response.status_code
# 4.请求的cookie
request_cookie = self.response.request._cookies
# 5.响应的cookie
response_cookie = self.response.cookies
print(data)
print(request_headers)
print(response_headers)
print(code)
print(request_cookie)
print(response_cookie)


RequestSpider().run()

6.5.传参

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import requests
# 参数自动转译
# url = 'http://www.baidu.com/s?wd=享健身'
url = 'http://www.baidu.com/s'
params = {
'wd': '享健身'
}
headers = {
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/537.36 '
'(KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36',
}
response = requests.get(url, headers=headers, params=params)

data = response.content.decode('utf-8')

with open('baidu.html', 'w') as f:
f.write(data)

# 发送post请求
# requests.post(url,data=(参数{}),json=(参数))
# 获取json数据 response.json()
# 获取文本数据 response.text
# chrome浏览器get请求参数:query post请求参数:formdata

6.6.ip代理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import requests

# 发送post请求
# data = {
#
# }
# requests.post(url='', data={})

# 内网需要认证
# auth = ('username', 'password')
# response = requests.get(url='', auth=auth)

url = 'http://www.baidu.com'
headers = {
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/537.36 (KHTML, like Gecko) '
'Chrome/69.0.3497.100 Safari/537.36'
}
free_proxy = {'http': '61.135.217.7:80'}

response = requests.get(url=url, headers=headers, proxies=free_proxy)
print(response.status_code)

6.7.取消ssl认证

1
2
3
4
5
6
7
8
9
10
11
12
13
import requests

url = 'https://test.xjshen.cn'
headers = {
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/537.36 (KHTML, like Gecko) '
'Chrome/69.0.3497.100 Safari/537.36'
}
# 因为https是第三方CA证书认证的
# 解决方法是:告诉web忽略证书访问
response = requests.get(url=url, headers=headers, verify=False)
data = response.content.decode('utf-8')

print(data)

6.8.cookies

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
import requests
# 1.代码登录
# 1.1 登录的网址
login_url = 'https://www.yaozh.com/login'
# 1.2 发生登录请求
login_form_data = {
'username': 'xiaomaoera12',
'pwd': 'lina081012',
'formhash': '36EBB186C4',
'backurl': 'https%3A%2F%2Fwww.yaozh.com%2F'
}
# 1.3 发送登录请求POST
# 带着参数发送post请求,添加请求头
headers = {
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/537.36 '
'(KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36',
}
# session类可以自动保存cookies === cookiejar
session = requests.session()
login_response = session.post(url=login_url, data=login_form_data, headers=headers)


# 2.代码带着cookie去访问 个人中心
center_url = 'https://www.yaozh.com/member/'
center_response = session.get(url=center_url, headers=headers)
# bytes --> str
data = center_response.content.decode('utf-8')
with open('yaozh.html', 'w') as f:
f.write(data)

总结一下:

发起get请求:requests.get(url=url, params=params)
发起post请求:requests.post(url=url, data=data)
通用的请求参数:requests.xxx(headers=headers, auth=auth, proxies=free_proxy, verify=False)
获取响应数据:response.context.decode(‘utf-8’)
response类型有:text、json、links…


7.获取资源(福利)

通过python爬取,你可以做很多功能,下面就简单给大家分享一个实用的功能。
下载资源到本地,资源包括图片、音频、视频...,只要是二进制文件,都可以爬,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import requests, os, click
# 获取资源并下载
def get_source(url, folder='./'):
if not os.path.exists(folder):
os.makedirs(folder)
name = url[url.rfind('.')-4:url.rfind('.')+4]
fpath = os.path.join(folder, name)
if not os.path.exists(fpath):
resp = requests.Session().get(url, stream=True)
length = int(resp.headers.get('content-length'))
label = 'Downloading {} {}kb'.format(name, int(length/1024))
with click.progressbar(length=length, label=label) as progressbar:
with open(fpath, 'wb') as f:
for chunk in resp.iter_content(chunk_size=1024):
if chunk:
f.write(chunk)
progressbar.update(1024)

python

只需传入想下载的任意资源链接,就可以下载:

1
2
3
4
5
6
7

# 图片
get_source('https://images.vmartaw.com/2018/08/08/preview2.jpg')
# 音频
get_source('https://m10.music.126.net/20181120134933/1984e9a53ec47a8b3847c06da3a3dc32/ymusic/2ed6/dbdd/97ae/dd9345a6d7320f7aefa2dc60301af89d.mp3')
# 视频
get_source('http://videos.cdn.change.so/video-1597fb3f39accd57c978b2620dd961ea.mp4')

至此爬虫篇入门就先介绍到这里,在后续篇幅中会深入讲解python爬虫的框架scrapy及使用它来存入mysql或elasticsearch。