一、Urllib

1.什么是互联网爬虫?

如果我们把互联网比作一张大的蜘蛛网,那一台计算机上的数据便是蜘蛛网上的一个猎物,而爬虫程序就是一只小蜘蛛,沿着蜘蛛网抓取自己想要的数据。

即通过一个程序来模拟浏览器,去向服务器发送请求,根据Url进行爬取网页,获取所需要的有用信息

2.爬虫核心

  1. 爬取网页:爬取整个网页 包含了网页中所有得内容

  2. 解析数据:将网页中你得到的数据 进行解析

  3. 难点:爬虫和反爬虫之间的博弈

3.爬虫的用途

  • 数据分析/人工数据集

  • 社交软件冷启动

  • 舆情监控

  • 竞争对手监控

4.爬虫分类

  • 通用爬虫:
    • 功能:访问网页‐>抓取数据‐>数据存储‐>数据处理‐>提供检索服务
    • robots协议:
    • 一个约定俗成的协议,添加robots.txt文件,来说明本网站哪些内容不可以被抓取,起不到限制作用,自己写的爬虫无需遵守
    • 缺点:
      • 抓取的数据大多是无用的
      • 不能根据用户的需求来精准获取数据
  • 聚焦爬虫
    • 功能:根据需求,实现爬虫程序,抓取需要的数据
    • 设计思路:
      • 确定要爬取的url
      • 模拟浏览器通过http协议访问url,获取服务器返回的html代码
      • 解析html字符串(根据一定规则提取需要的数据)

5.反爬手段

  1. User‐Agent:

    1. User Agent中文名为用户代理,简称 UA,它是一个特殊字符串头,使得服务器能够识别客户使用的操作系统及版

      本、CPU 类型、浏览器及版本、浏览器渲染引擎、浏览器语言、浏览器插件等。

  2. 代理IP

    1. 西次代理
    2. 快代理
    3. 什么是高匿名、匿名和透明代理?它们有什么区别?
      1. 使用透明代理,对方服务器可以知道你使用了代理,并且也知道你的真实IP。
      2. 使用匿名代理,对方服务器可以知道你使用了代理,但不知道你的真实IP。
      3. 使用高匿名代理,对方服务器不知道你使用了代理,更不知道你的真实IP。
  3. 验证码访问

    1. 打码平台
    2. 云打码平台
    3. 超级🦅
  4. 动态加载网页 网站返回的是js数据 并不是网页的真实数据

    1. selenium驱动真实的浏览器发送请求
  5. 数据加密

    1. 分析js代码

6.urllib库使用

6.1 urllib的基本使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 使用urllib来获取百度首页的源码
#(0) 导包
import urllib.request

#(1) 定义url
url = "http://www.baidu.com"

#(2) 模拟浏览器向服务器发送请求并获取响应
response = urllib.request.urlopen(url)

#(3) 获取响应中的页面的源码
#read方法 返回的字节形式的二进制数据
#将二进制数据转换为字符串
#解码 decode('编码的格式')
content = response.read().decode('utf-8')


#(4) 打印数据
print(content)

6.2 一个类型和六个方法

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
#一个类型 HTTPResponse
#六个方法 read readline readlines getcode geturl getheaders

import urllib.request

url = 'http://www.baidu.com'

#模拟浏览器向服务器发送请求
response = urllib.request.urlopen(url)\

#一个类型和六个方法

#response是HTTPResponse类型
print(type(response))

#按照一个字节一个字节的读数据
# content = response.read()
# print(content)

#返回多少个字节,5代表返回5个字节
# content = response.read(5)
# print(content)

#读取一行
# content = response.readline()
# print(content)

#读取多行
# content = response.readlines()
# print(content)

#返回状态码
print(response.getcode())

#返回的是url地址
print(response.geturl())

#获取状态信息
print(response.getheaders())

6.3 下载 网页、图片、视频

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

url_page = "http://www.baidu.com"

#下载网页
#url代表的是下载的路径,filename代表文件的名字
# urllib.request.urlretrieve(url=url_page,filename='baidu.html')


#下载图片
url_img = 'https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fup.enterdesk.com%2Fedpic%2F2d%2F98%2F4e%2F2d984eafff42a790cbdc463b35e7e1ab.jpg&refer=http%3A%2F%2Fup.enterdesk.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1651026550&t=31e18a817719f780dee95ef36e2666c5'
# urllib.request.urlretrieve(url_img,'lisa.jpg')


#下载视频
url_video = 'https://vd3.bdstatic.com/mda-kjtx64epufgk8zw5/sc/cae_h264_nowatermark/1604104149/mda-kjtx64epufgk8zw5.mp4?v_from_s=hkapp-haokan-nanjing&auth_key=1648436966-0-0-c4052b4fdee46ddac2e5399be644e0ee&bcevod_channel=searchbox_feed&pd=1&cd=0&pt=3&logid=2366050261&vid=6647036806223333961&abtest=100815_1-101130_1-17451_1-3000221_7&klogid=2366050261'

urllib.request.urlretrieve(url_video,'Lisa.mp4')

7.请求对象的定制

7.1 url的组成

http/https www.baidu.com 80/443 s wd = Lisa #

协议 主机 端口号 路径 参数 锚点

常见的端口:

  • http 80
  • https 443
  • mysql 3306
  • redis 6379
  • Tomcat 8080

7.2 UA介绍:

UA介绍:User Agent中文名为用户代理,简称 UA,它是一个特殊字符串头,使得服务器能够识别客户使用的操作系统及版本、CPU 类型、浏览器及版本。浏览器内核、浏览器渲染引擎、浏览器语言、浏览器插件等。

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

url = "https://www.baidu.com/"

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'
}

#因为urlopen方法中不能存储字典,所以headers不能传递进去
#所以需要进行请求对象的定制
request = urllib.request.Request(url=url,headers=headers)

response = urllib.request.urlopen(request)

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

print(content)

8.编解码

8.1 编解码的演变

由于计算机是美国人发明的,因此,最早只有127个字符被编码到计算机里,也就是大小写英文字母、数字和一些符号,

这个编码表被称为ASCII编码,比如大写字母A的编码是65,小写字母z的编码是122。

但是要处理中文显然一个字节是不够的,至少需要两个字节,而且还不能和ASCII编码冲突,

所以,中国制定了GB2312编码,用来把中文编进去。

你可以想得到的是,全世界有上百种语言,日本把日文编到Shift_JIS里,韩国把韩文编到Euc‐kr里,

各国有各国的标准,就会不可避免地出现冲突,结果就是,在多语言混合的文本中,显示出来会有乱码。

因此,Unicode应运而生。Unicode把所有语言都统一到一套编码里,这样就不会再有乱码问题了。

Unicode标准也在不断发展,但最常用的是用两个字节表示一个字符(如果要用到非常偏僻的字符,就需要4个字节)。

现代操作系统和大多数编程语言都直接支持Unicode。

8.2 get请求方式1:urllib.parse.quote()

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
import urllib.request
import urllib.parse
#url = 'https://www.baidu.com/s?ie=UTF-8&wd=%E6%9E%97%E4%BF%8A%E6%9D%B0'
#复制进来发现林俊杰变为了%E6%9E%97%E4%BF%8A%E6%9D%B0
#这是因为浏览器用的是ASCII编码,而python用的是Unicode编码,所以需要进行转换
url = 'https://www.baidu.com/s?ie=UTF-8&wd='

name = urllib.parse.quote('林俊杰')
#拼接url
url = url + name


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'
}

#定制请求对象
request = urllib.request.Request(url=url,headers=headers)

#模拟浏览器向服务器发送请求
response = urllib.request.urlopen(request)


#获取响应内容
content = response.read().decode('utf-8')

#打印数据
print(content)

8.2 get请求方式2:urllib.parse.urlencode()

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
44
#-*-coding:utf-8-*-
#@Time:2022/3/2814:26
#@Author:陈 玉 皓
#@File:urlencode_1.py
#@Sofeware:PyCharm
import urllib.request
import urllib.parse
#urlencode应用场景,多个参数的时候

#例:https://www.baidu.com/s?wd=周杰伦&sex=男&location=中国台湾省

base_url = 'https://www.baidu.com/s?'

data = {
'wd':'周杰伦',
'sex':'男',
'location':'中国台湾省'
}


new_data = urllib.parse.urlencode(data)

print(new_data)

#请求资源路径
url = base_url + new_data
print(url)

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'
}

#定制请求对象
request = urllib.request.Request(url=url,headers=headers)

#模拟浏览器向服务器发送请求
response = urllib.request.urlopen(request)


#获取响应内容
content = response.read().decode('utf-8')

#打印数据
print(content)

9.ajax的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
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# -*-coding:utf-8-*-
# @Time:2022/3/2914:49
# @Author:陈 玉 皓
# @File:douban2.py
# @Sofeware:PyCharm

import urllib.parse
import urllib.request


def create_request(page):
base_url = 'https://movie.douban.com/j/chart/top_list?type=5&interval_id=100%3A90&action=&'

data = {
'start': (page - 1) * 20,
'limit': 20
}

data = urllib.parse.urlencode(data)

url = base_url + data

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'
}
#请求对象的定制
request = urllib.request.Request(url=url,headers=headers)
return request

#获取网页源代码
def get_content(request):
response = urllib.request.urlopen(request)
content = response.read().decode('utf-8')
return content


def down_load(page, content):
# open方法默认情况下使用的是gbk的编码
# 如果想保存汉字,需要在open方法中指定编码格式为utf-8
with open('douban_' + str(page) + '.json', 'w', encoding='utf-8') as fp:
fp.write(content)


# 程序的入口
if __name__ == '__main__':
start_page = int(input('请输入起始的页码:'))
end_page = int(input('请输入结束的页码:'))

for page in range(start_page, end_page + 1):
# 每一页都有自己的请求定制
request = create_request(page)
# 获取响应数据
content = get_content(request)
# 下载
down_load(page,content)

10.ajax的post请求

KFC地点查询

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
44
45
46
47
48
49
50
51
52
53
# -*-coding:utf-8-*-
# @Time:2022/3/2916:33
# @Author:陈 玉 皓
# @File:kfcdemo.py
# @Sofeware:PyCharm
import urllib.request
import urllib.parse


def create_request(location,page):
url = 'http://www.kfc.com.cn/kfccda/ashx/GetStoreList.ashx?op=cname'
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'
}
data = {
'cname': location,
'pid':'',
'pageIndex': page,
'pageSize': '10'
}
#post方式编码
data = urllib.parse.urlencode(data).encode('utf-8')

request = urllib.request.Request(url=url,data=data,headers=headers)

return request

def get_content(request):
response = urllib.request.urlopen(request)
content = response.read().decode('utf-8')
return content


def down_load(content,page):
with open('kfc_'+str(page)+'.json','w',encoding='utf-8') as f:
f.write(content)





if __name__ == '__main__':
localtion = input('请输入你要查询的省份或者城市:')
start_page = int(input('请输入起始页码:'))
end_page = int(input('请输入结束页码:'))

for page in range(start_page,end_page + 1):
# 定制请求对象
request = create_request(localtion,page)
#获取响应内容
content = get_content(request)
#下载每一页的数据
down_load(content,page)

11.UrlError\HTTPError

简介:

  1. HTTPError类是URLError类的子类

  2. 导入的包urllib.error.HTTPError urllib.error.URLError

  3. http错误:http错误是针对浏览器无法连接到服务器而增加出来的错误提示。引导并告诉浏览者该页是哪里出了问题。

  4. 通过urllib发送请求的时候,有可能会发送失败,这个时候如果想让你的代码更加的健壮,可以通过try‐

except进行捕获异常,异常有两类,URLError\HTTPError

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import urllib.request
import urllib.error
#url = https://blog.csdn.net/TZ45678/article/details/123486485
#乱改一下会出异常
url = 'https://blog.csdn.net/TZ45678/article/details/123486485sdfasfdasdf'

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'
}
try:
request = urllib.request.Request(url=url,headers=headers)
response = urllib.request.urlopen(request)
content = response.read().decode('utf-8')
print(content)

except urllib.error.HTTPError:
print('系统正在升级...')

12.cookie登录