一、python基础

1、注释

1
2
3
4
5
6
7
8
9
# 单行注释

"""
多行注释
"""

'''
多行注释
'''

2、变量以及数据类型

在python中,不需要定义变量的类型,系统会自动根据变量的值来确定变量的类型

【List(列表)———Java中的数组】【Tuple(元组)———】

image-20210902114204961

2.1、变量定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#数字类型【 int 和 float 】
a = 123
b = 12.8

# 布尔类型
c = False
d = True

# 字符串类型
e = "今天天气真好"
f = '今天天气不好'

# List列表类型【相当于Java中的Object数组或集合】
g = [1, "字符串2", 3, '字符串4']

# Tuple(元组)【相当于Java中的Object数组或集合】
h = (1, "字符串2", 3, '字符串4')

# Dictionary(字典)【相当于Java中的Map集合】
i = {'age': 18, 'name': '张三'}

2.2、查看变量的数据类型

使用type来查看变量的数据类型

1
2
a = 123
print(type(a))

3、类型转换

函数 说明
int(x) 将x转换为一个整数
float(x) 将x转换为一个浮点数
str(x) 将对象 x 转换为字符串
bool(x) 将对象x转换成为布尔值
1
2
3
4
5
6
7
# 以下情况转换为bool类型全为false
print(bool(''))
print(bool(""))
print(bool(0))
print(bool({}))
print(bool([]))
print(bool(()))

4、运算符

4.1、算数运算符

下面以a=10 ,b=20为例进行计算

运算符 描述 实例
+ 两个对象相加 a + b 输出结果 30
- 得到负数或是一个数减去另一个数 a - b 输出结果 -10
* 两个数相乘或是返回一个被重复若干次的字符串 a * b 输出结果 200
/ b / a 输出结果 2
// 取整数 返回商的整数部分 9//2 输出结果 4 , 9.0//2.0 输出结果 4.0
% 取余 返回除法的余数 b % a 输出结果 0
** 指数 a**b 为10的20次方
() 小括号 提高运算优先级,比如: (1+2) * 3

==注意:混合运算时,优先级顺序为: * 高于 / % // 高于 + - ,为了避免歧义,建议使用 () 来处理运 算符优先级。 并且,不同类型的数字在进行混合运算时,整数将会转换成浮点数进行运算。在字符串中使用+是字符串拼接==

4.2、赋值运算符

运算符 描述 实例
= 赋值运算符 把 = 号右边的结果 赋给 左边的变量,如 num = 1 + 2 * 3,结果num的值为7
1
2
3
4
a = 10
b = c = 2
# 以上两种赋值方式在其他编程语言中都能实现,下面这种方式是python中特有的
d, e, f = 1, 2, 3

4.3、复合赋值运算符

运算符 描述 实例
+= 加法赋值运算符 c += a 等效于 c = c + a
-= 减法赋值运算符 c -= a 等效于 c = c - a
*= 乘法赋值运算符 c = a 等效于 c = c a
/= 除法赋值运算符 c /= a 等效于 c = c / a
//= 取整除赋值运算符 c //= a 等效于 c = c // a
%= 取模赋值运算符 c %= a 等效于 c = c % a
**= 幂赋值运算符 c = a 等效于 c = c ** a

4.4、比较运算符

运算符 描述 实例
== 等于:比较对象是否相等 (a == b) 返回 False
!= 不等于:比较两个对象是否不相等 (a != b) 返回 true
> 大于:返回x是否大于y (a > b) 返回 False
>= 大于等于:返回x是否大于等于y (a >= b) 返回 False
< 小于:返回x是否小于y。所有比较运算符返回1表示真,返回0表示假。这分别与特 殊的变量True和False等价 (a < b) 返回 true
<= 小于等于:返回x是否小于等于y (a <= b) 返回 true

4.5、逻辑运算符

运算符 逻辑表达式 描述 实例
and x and y 只要有一个运算数是False,结果就是False; 只有所有的运算数都为True时,结果才是True 做取值运算时,取第一个为False的值,如果所有的值 都为True,取最后一个值 True and True and False—> 结果为False True and True and True—> 结果为True
or x or y 只要有一个运算数是True,结果就是True; 只有所有的运算数都为False时,结果才是False 做取值运算时,取第一个为True的值,如果所有的值都 为False,取最后一个值 False or False or True—>结 果为True False or False or False—>结 果为False
not not x 布尔”非” - 如果 x 为 True,返回 False 。如果 x 为 False,它返回 True。 not True —> False

性能优化

1
2
3
4
5
6
7
a = 11

# and的性能优化,当前的结果是False的情况下,那么后面的代码就不再执行了
a > 10 and print('会输出')

# or的性能优化,当前面的结果是True的情况下,后面的代码就不再执行了
a == 11 or print('不会输出')

5、输入和输出

5.1、输出

普通输出

1
2
3
4
print('aaaa')

a = "这是拼接后的字符串"
print("字符串1" + a)

格式化输出

1
2
3
4
5
age = 10
print("我今年%d岁" % age)

name = "红浪漫晶哥"
print("我的姓名是%s, 年龄是%d" % (name, age))

5.2、输入

1
2
password = input('请输入密码:')
print('输入的密码为:%s' % password)

6、流程控制语句

6.1、if

格式

1
2
if 要判断的条件:
条件成立时,要做的事情

示例

1
2
3
a = 10
if a > 5:
print('条件成立,输出了')

6.2、if-else

格式

1
2
3
4
if 要判断的条件:
条件成立时,执行的操作
else:
条件不成立时,候执行的操作

示例

1
2
3
4
5
a = 10
if a > 0:
print("条件成立")
else:
print("条件不成立")

6.3、elif

格式

1
2
3
4
5
6
7
a = 10
if 判断的条件:
条件成立时,执行的操作
elif 判断的条件:
条件成立时,执行的操作
else:
条件成立时,执行的操作

示例

1
2
3
4
5
6
7
a = 10
if a > 0:
print("a>0")
elif a < -10:
print('a<-10')
else:
print('其他条件')

6.4、for

格式

1
2
for 临时变量 in 列表或者字符串等可迭代对象:
循环满足条件时执行的代码

示例

1
2
3
4
5
6
7
# 循环字符串
for s in "hello":
print(s)
# 遍历列表
items = [1, 2, 3, 4]
for item in items:
print(item)

6.5、range

range可以生成一个列表用于循环,它可以传递三个参数,分别表示 起始、结束和步长

示例

1
2
3
for item in range(1, 10, 3):
print(item)
# 输出:1,4,7

7、数据类型高级

7.1、字符串高级

  • len:获取字符串的长度
  • find:查找指定内容在字符串中是否存在,不存在返回-1,存在返回第一次出现的位置
  • startswith endswith:判断以谁开头/结尾,返回bool值
  • count:返回指定内容在字符串中出现的次数
  • replace:替换内容,两个参数,第一个,替换前的值,第二个,替换后的值
  • split:切割字符串,会将切割后的结果返回为列表
  • upper lower:upper(小写全部变为大写,大写不变),lower(大写变为小写,小写不变)
  • strip:去除字符串的前后空格,中间的空格不会去除
  • join:字符串拼接,和正常的拼接不一样 ,测试一下就知道了

7.2、列表高级

7.2.1、列表添加

  • append 在末尾添加元素 ,会修改原来的数组
  • insert 在指定位置插入元素 ,会修改原来的数组
  • extend 合并两个列表 ,会修改原来的数组

示例

1
2
3
4
5
6
7
8
9
10
a = [1, 2, 3]
a.append(4)
print(a) # [1, 2, 3, 4]

a.insert(11, 11)
print(a) # [1, 2, 3, 4, 11]

b = [22, 33]
a.extend(b)
print(a) # [1, 2, 3, 4, 11, 22, 33]

7.2.2、列表修改

找到指定元素的下标重新赋值

示例

1
2
3
a = [1, 2, 3]
a[1] = 231313
print(a) # [1, 231313, 3]

7.2.3、列表查询

  • in(存在),如果存在那么结果为true,否则为false
  • not in(不存在),如果不存在那么结果为true,否则false

格式

1
print(判断的值 in / not in 列表)

示例

1
2
3
a = [1, 2, 3]
print(1 in a) # True
print(11 in a) # False

7.2.4、列表删除

  • del:根据下标进行删除
  • pop:删除最后一个元素
  • remove:根据元素的值进行删除
1
2
3
4
5
6
7
8
9
10
11
a = [1, 2, 3, 4]
del a[1]
print(a) # [1, 3, 4]

a = [1, 2, 3, 4]
a.pop()
print(a) # [1, 2, 3]

a = [1, 2, 3, 4]
a.remove(1)
print(a) # [2, 3, 4]

7.3、元组高级

==Python的元组与列表类似,不同之处在于元组的元素不能修改。元组使用小括号,列表使用方括号。==

==当元组中只有一个元素的时候,必须在最后一个元素后面添加一个,==

7.3.1、元组查询

1
2
a = (1, 2, 3, 4)
print(a[1]) # 2

7.4、切片

切片就是截取,截取部分字符串,获取元组或列表中的部分数据,字符串,列表,元组都支持切片

格式

1
2
切片的语法:[起始:结束:步长],也可以简化使用 [起始:结束]
注意:选取的区间从"起始"位开始,到"结束"位的前一位结束(不包含结束位本身),步长表示选取间隔

示例

1
2
3
4
5
6
7
s = 'Hello World!'
print(s)
print(s[4]) # 获取指定位置的值,输出:o
print(s[3:7]) # 从第几个位置开始截取,截取到第几个,输出:lo W
print(s[5:]) # 从第几个位置开始截取,截取到最后一个,输出: World!
print(s[:5]) # 从起始位置开始,取到 下标为4的前一个元素(不包括结束位本身),输出:Hello
print(s[1:5:2]) # 从下标为1开始,取到下标为5的前一个元素,步长为2(不包括结束位本身)输出:el

7.5、字典高级

7.5.1、字典查询

除了使用key查找数据,还可以使用get来获取数据

1
2
3
4
5
6
7
person = {'name': '韩信', 'age': 18, 'gender': '男'}

print(person.get('name')) # 输出:韩信
print(person.get('error')) # 不报错。输出:None

print(person['gender']) # 当键不存在的时候,会报错。输出:男
print(person['error']) # 报 KeyError 错误

7.5.2、字典修改

1
2
3
person = {'name': '韩信', 'age': 18, 'gender': '男'}
person['name'] = '法外狂徒张三'
print(person.get('name')) # 输出:法外狂徒张三

7.5.3、字典添加

1
2
3
person = {'name': '韩信', 'age': 18}
person['gender'] = '男'
print(person.get('gender')) # 输出:男

7.5.4、字典删除

  • del :删除指定的元素 / 删除整个字典
  • clear():清空整个字典

del和clear删除字典的区别为:del删除整个字典,如果删除之后还调用,会报未定义错误。clear则是将字典中的元素全部删除,但是字典还是存在的

1
2
3
4
5
6
7
8
9
10
person = {'name': '韩信', 'age': 18}

del person['age'] # 删除指定key的元素
print(person) # 输出:{'name': '韩信'}

person.clear() # 清除字典中的所有键值对
print(person) # 输出:{}

del person # 删除整个字典,把整个变量都删除
print(person) # 报错:NameError: name 'person' is not defined

7.5.5、字典遍历

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
person = {'name': '韩信', 'age': 18}

"""
遍历 key
输出:
name
age
"""
for item in person.keys():
print(item)

"""
遍历 value
输出:
韩信
18
"""
for item in person.values():
print(item)

"""
遍历键值对:(key,value)
输出:
('name', '韩信')
('age', 18)
"""
for item in person.items():
print(item)

8、函数

8.1、函数定义

格式

1
2
def 函数名():
代码

示例

1
2
3
def personInfo():
print('name:' + '法外狂徒张三')
print('age:' + '18')

8.2、函数调用

1
2
3
4
5
6
def personInfo():
print('name:' + '法外狂徒张三')
print('age:' + '18')


personInfo()

8.3、函数参数

函数的参数可以给默认值,当没有值传入的时候,会自动使用默认值,,如果没有默认值,则在调用的时候必须传值,也可以在调用函数的时候给指定的参数传值

固定参数

1
2
3
4
5
6
7
8
9
10
11
def personInfo(gender, name='李白', age=20):
print('gender:%s' % gender) # 输出:gender:男
print('name:%s' % name) # 输出:name:韩信
print('age:%d' % age) # 输出:age:22


#位置参数传参
personInfo('男', '韩信') # 不传入对应的值,如果有默认值,则不报错,否则报错

#关键字传参
personInfo(gender='女', name='杨玉环') # 给指定的变量赋值,如果有一个使用了指定传值,其他都要指定

可变参数

python中会将最后没有变量接收的参数会使用元组统一接收

1
2
3
4
5
6
7
def personInfo(name, *aaa):
print(name) # 输出:韩信
print(aaa) # 输出:(1, 2, 3, 45, 5)
print(type(aaa)) # 输出:<class 'tuple'>


personInfo('韩信', 1, 2, 3, 45, 5)

8.4、函数返回值

1
2
3
4
5
def personInfo(age):
return age + 1


print(personInfo(1)) # 输出:2

8.5、局部变量

1
2
3
4
5
6
def personInfo(age):
b = 2 # 局部变量
return age + b


print(personInfo(1)) # 输出:3

8.6、全局变量

1
2
3
4
5
6
7
8
9
a = 1  # 全局变量


def personInfo(age):
b = 2 # 局部变量
return age + b + a


print(personInfo(1)) # 输出:4

10、文件

10.1、文件的打开与关闭

10.1.1、打开文件/创建文件

格式

1
2
3
4
5
6
7
# 当文件存在时是打开,当文件不存在时,创建文件
open(文件路径,模式)
'''
模式:
w:可写
r:可读
'''

示例

1
2
# 指定文件,设置操作模式,设置字符编码
open(file='test1.txt', mode='r', encoding='utf-8')

文件路径

  • 绝对路径:指的是绝对位置,完整地描述了目标的所在地,所有目录层级关系是一目了然的。 、
    • 例如:E:\python,从电脑的盘符开始,表示的就是一个绝对路径。
  • 相对路径:是从当前文件所在的文件夹开始的路径。
    • test.txt ,是在当前文件夹查找 test.txt 文件
    • ./test.txt ,也是在当前文件夹里查找 test.txt 文件, ./表示的是当前文件夹。
    • ../test.txt ,从当前文件夹的上一级文件夹里查找 test.txt 文件。 ../表示的是上一级文件夹
    • demo/test.txt ,在当前文件夹里查找 demo 这个文件夹,并在这个文件夹里查找 test.txt 文件。

访问模式

访问模式 说明
r 以只读方式打开文件。文件的指针将会放在文件的开头。如果文件不存在,则报错。这是默认模式
w 打开一个文件只用于写入。如果该文件已存在则将其覆盖。如果该文件不存在,创建新文件。
a 打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。也就是说,新的内容将 会被写入到已有内容之后。如果该文件不存在,创建新文件进行写入。
r+ 打开一个文件用于读写。文件指针将会放在文件的开头。
w+ 打开一个文件用于读写。如果该文件已存在则将其覆盖。如果该文件不存在,创建新文件。
a+ 打开一个文件用于读写。如果该文件已存在,文件指针将会放在文件的结尾。文件打开时会是追加模 式。如果该文件不存在,创建新文件用于读写。
rb 以二进制格式打开一个文件用于只读。文件指针将会放在文件的开头
wb 以二进制格式打开一个文件只用于写入。如果该文件已存在则将其覆盖。如果该文件不存在,创建新 文件
ab 以二进制格式打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。也就是 说,新的内容将会被写入到已有内容之后。如果该文件不存在,创建新文件进行写入。
rb+ 以二进制格式打开一个文件用于读写。文件指针将会放在文件的开头。
wb+ 以二进制格式打开一个文件用于读写。如果该文件已存在则将其覆盖。如果该文件不存在,创建新文 件。
ab+ 以二进制格式打开一个文件用于读写。如果该文件已存在,文件指针将会放在文件的结尾。如果该文 件不存在,创建新文件用于读写。

10.2、文件的读写

写数据(write)

如果文件不存在,那么创建;如果存在那么就先清空,然后写入数据

1
2
3
4
# 指定文件,设置操作模式,设置字符编码
f = open(file='test1.txt', mode='w', encoding='utf-8')
f.write("乱码了吗")
f.close()

读数据(read)

1
2
3
4
f = open(file='test1.txt', mode='r', encoding='utf-8')
result = f.read(5) # 最多读取5个数据
print(result)
f.close()

读数据(readlines)

readlines可以按照行的方式把整个文件中的内容进行一次性读取,并且返回的是一个列表,其中每一行为列表的 一个元素。换行也会读取

1
2
3
4
5
# 指定文件,设置操作模式,设置字符编码
f = open(file='test1.txt', mode='r', encoding='utf-8')
result = f.readlines() # 最多读取5个数据
print(result)
f.close()

10.3、序列化和反序列化

通过文件操作,我们可以将字符串写入到一个本地文件。但是,如果是一个对象(例如列表、字典、元组等),就无 法直接写入到一个文件里,需要对这个对象进行序列化,然后才能写入到文件里。

设计一套协议,按照某种规则,把内存中的数据转换为字节序列,保存到文件,这就是序列化,反之,从文件的字 节序列恢复到内存中,就是反序列化

对象—-》字节序列 === 序列化

字节序列—》对象 ===反序列化

Python中提供了JSON这个模块用来实现数据的序列化和反序列化

JSON模块

JSON(JavaScriptObjectNotation, JS对象简谱)是一种轻量级的数据交换标准。JSON的本质是字符串。

使用JSON实现序列化

JSON提供了dump和dumps方法,将一个对象进行序列化。

dumps方法的作用是把对象转换成为字符串,它本身不具备将数据写入到文件的功能。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import json
file = open('names.txt', 'w')
names = ['zhangsan', 'lisi', 'wangwu', 'jerry', 'henry', 'merry', 'chris']
# file.write(names) 出错,不能直接将列表写入到文件里

# 可以调用 json的dumps方法,传入一个对象参数
result = json.dumps(names)

# dumps 方法得到的结果是一个字符串
print(type(result)) # <class 'str'>

# 可以将字符串写入到文件里
file.write(result)
file.close()

dump方法可以在将对象转换成为字符串的同时,指定一个文件对象,把转换后的字符串写入到这个文件里

1
2
3
4
5
6
7
8
import json

file = open('names.txt', 'w')
names = ['zhangsan', 'lisi', 'wangwu', 'jerry', 'henry', 'merry', 'chris']

# dump方法可以接收一个文件参数,在将对象转换成为字符串的同时写入到文件里
json.dump(names, file)
file.close()

使用JSON实现反序列化

使用loads和load方法,可以将一个JSON字符串反序列化成为一个Python对象。

loads方法需要一个字符串参数,用来将一个字符串加载成为Python对象。

1
2
3
4
5
import json

# 调用loads方法,传入一个字符串,可以将这个字符串加载成为Python对象
result = json.loads('["zhangsan", "lisi", "wangwu", "jerry", "henry", "merry", "chris"]')
print(type(result)) # <class 'list'>

load方法可以传入一个文件对象,用来将一个文件对象里的数据加载成为Python对象。

1
2
3
4
5
6
7
8
9
import json

# 以可读方式打开一个文件
file = open('names.txt', 'r')

# 调用load方法,将文件里的内容加载成为一个Python对象
result = json.load(file)
print(result)
file.close()

11、异常

格式

1
2
3
4
try:
可能会出现异常的代码块
except 异常的类型:
出现异常以后的处理语句

示例

1
2
3
4
try:
a = 10 / 0
except ZeroDivisionError:
print("程序出异常了")

二、爬虫技术

1、urllib

1.1、urllib库使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
urllib.request.urlopen() 模拟浏览器向服务器发送请求
response 服务器返回的数据
response的数据类型是HttpResponse
字节‐‐>字符串
解码decode
字符串‐‐>字节
编码encode
read() 字节形式读取二进制 扩展:rede(5)返回前几个字节
readline() 读取一行
readlines() 一行一行读取 直至结束
getcode() 获取状态码
geturl() 获取url
getheaders() 获取headers
urllib.request.urlretrieve()
请求网页
请求图片
请求视频

一个类型和六个方法

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
# 引入包
import urllib.request

# 1、定义一个url 就是需要访问的地址
url = "http://www.baidu.com"

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

# 3、一个类型和六个方法

# print(type(response)) # 输出:<class 'http.client.HTTPResponse'>

# 按照一个一个字节去读,读取全部字节
# content = response.read()

# 按照一个一个字节去读,读取字节个数为自定个数
# content = response.read(5)

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

# 读取全部
# content = response.readlines()

# 获取返回的状态码
# statusCode = response.getcode()

# 返回请求的地址
# reqUrl = response.geturl()

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

网页、图片、视频下载

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

# 下载网页
# urlPage = 'http://www.baidu.com'
# urllib.request.urlretrieve(urlPage, '百度首页.html')

# 下载图片
# urlImage = '图片地址'
# urllib.request.urlretrieve(url=urlImage, filename='图片.webp')

# 下载视频
# urlVideo = '视频地址'
# urllib.request.urlretrieve(url=urlVideo, filename='视频.mp4')

1.2、请求对象定制

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

URL组成

1
2
3
# https://www.baidu.com/s?wd=李白
# http/https www.baidu.com 80/443 s wd=李白 #
协议 主机 端口号 路径 参数 锚点

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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/93.0.4577.63 Safari/537.36'
}
# 设置请求对象
request = urllib.request.Request(url=url, headers=headers)
# 访问地址
response = urllib.request.urlopen(request)

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

print(content)

1.3、编解码

1
2
3
4
5
6
7
8
9
10
'''编码集的演变‐‐‐
由于计算机是美国人发明的,因此,最早只有127个字符被编码到计算机里,也就是大小写英文字母、数字和一些符号,
这个编码表被称为ASCII编码,比如大写字母A的编码是65,小写字母z的编码是122。
但是要处理中文显然一个字节是不够的,至少需要两个字节,而且还不能和ASCII编码冲突,
所以,中国制定了GB2312编码,用来把中文编进去。
你可以想得到的是,全世界有上百种语言,日本把日文编到Shift_JIS里,韩国把韩文编到Euc‐kr里,
各国有各国的标准,就会不可避免地出现冲突,结果就是,在多语言混合的文本中,显示出来会有乱码。
因此,Unicode应运而生。Unicode把所有语言都统一到一套编码里,这样就不会再有乱码问题了。
Unicode标准也在不断发展,但最常用的是用两个字节表示一个字符(如果要用到非常偏僻的字符,就需要4个字节)。
现代操作系统和大多数编程语言都直接支持Unicode。'''

1.3.1、Get请求参数编码

使用quoto、urlencode将参数设置为Unicode编码,否则会报错

quoto、urlencode的区别为:quoto需要一个一个拼接,urlencode可以将一个字典中的参数一次性拼接

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

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

url = 'https://www.baidu.com/s?wd='

# 将url的请求参数设置为Unicode编码
url = url + urllib.parse.quote('周杰伦')

# 请求对象订单
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.63 Safari/537.36'
}
request = urllib.request.Request(url=url, headers=headers)

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

# 获取响应的数据
content = response.read().decode('utf-8')

print(content)

get请求方式: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
import urllib.request
import urllib.parse

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

data = {
'wd': '周杰伦',
'aaa': None
}
data = urllib.parse.urlencode(data)

# 将url的请求参数设置为Unicode编码
url = url + data

# 请求对象订单
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.63 Safari/537.36'
}
request = urllib.request.Request(url=url, headers=headers)

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

# 获取响应的数据
content = response.read().decode('utf-8')

print(content)

1.3.2、Post请求

post请求方式

  • 百度翻译简单翻译

    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 urllib.parse
    import json

    url = 'https://fanyi.baidu.com/sug'

    headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.63 Safari/537.36'
    }

    keyword = input('输入要查询的单词:')
    data = {
    'kw': keyword
    }


    # post请求还需要再调用一次encode()方法
    data = urllib.parse.urlencode(data).encode('utf-8')

    # post的请求参数,是不会拼接在url后面的,二十需要放在请求对象定制的参数中
    request = urllib.request.Request(url=url, data=data, headers=headers)

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

    # 获取响应的数据
    content = response.read().decode('utf-8')

    # 将返回的字符串转换为JSON对象
    print(json.loads(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
    32
    33
    34
    35
    36
    37
    import urllib.request
    import urllib.parse
    import json

    url = 'https://fanyi.baidu.com/v2transapi?from=en&to=zh'

    headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.63 Safari/537.36',
    'Cookie': 'BIDUPSID=112CB6BA1DD43128CF60D2C21C3891FA; PSTM=1630486205; BAIDUID=112CB6BA1DD43128A6786F0F3F6C98E3:FG=1; BDORZ=B490B5EBF6F3CD402E515D22BCDA1598; __yjs_duid=1_e631d45aca5951ce99da01dbce8657761630487228976; REALTIME_TRANS_SWITCH=1; FANYI_WORD_SWITCH=1; HISTORY_SWITCH=1; SOUND_PREFER_SWITCH=1; SOUND_SPD_SWITCH=1; Hm_lvt_64ecd82404c51e03dc91cb9e8c025574=1630487229,1630489993,1630644060; delPer=0; PSINO=7; H_PS_PSSID=34434_34496_31660_33848_34524_34092_34107_26350_34426_34319_34473; BA_HECTOR=8k21a424248ka504cq1gj3atu0r; Hm_lpvt_64ecd82404c51e03dc91cb9e8c025574=1630647380; ab_sr=1.0.1_MDRkZDYwZjI4MzQzYjYyNTU5YTYwYTBmNWNkNTYwY2EwZTM1MWVmZDc5NTIwMmZhN2UxMWFmNDI5NzZmZWFjMDBkNDRiZTE2MTIxNjdhZDBhYWU2NDE1NGQ2M2FlN2ZhNThmYTQ2ODIyOGMzMDY0MWE2ZWQ2MjFmZjBlZWJkMmRjMzE3ZDhmMDYwNTFhODEyNzA5YWFjY2FiNjU4OGY2ZA==; __yjs_st=2_YmE3ZWYzYjZhODc4NTYxOWU4ZWQ2OTg2NTdmMzVjYmJkYjlkMmQ3YmZhYzliYWExMTI0NDAyNGY3NWEyMmU4MTk0OWQ2ODRmMDJmYzE0NGExN2RhYTg2ZjA3MTk2MjZmYjBiMjE2MTdjNWE0NzNmZGJjMjVlODYwMTkwYjZjZjJmMjAyOTBkOTdiZmVkOGNjNWI3MzZmOTdmZGNhNTM5MjA5ZGFiN2E1ZTRiYzM3ZDYwNzk1MTZmOWQ0MTdmMjhiZWFlNjg5MDE5ZGI5MGIwNjA3ZTI0NTcyMTA2MWJkMDY0NWM0ZjI1MmFmNWMzOGY5NTExMWQxZjZiNDkyYzcyN2RlZjFiNjI1ODMzOWMwOGIxNWUxODVmNzVjYjA3NTcxXzdfNGFhOWMxZjc='
    }

    keyword = input('输入要查询的单词:')
    data = {
    'from': 'en',
    'to': 'zh',
    'query': 'appl',
    'transtype': 'realtime',
    'simple_means_flag': '3',
    'sign': '466982.246551',
    'token': '96365d8cce65e1a98a1638ee4563dc36',
    'domain': 'common',
    }

    # post请求还需要再调用一次encode()方法
    data = urllib.parse.urlencode(data).encode('utf-8')

    # post的请求参数,是不会拼接在url后面的,二十需要放在请求对象定制的参数中
    request = urllib.request.Request(url=url, data=data, headers=headers)

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

    # 获取响应的数据
    content = response.read().decode('utf-8')

    # 将返回的字符串转换为JSON对象
    print(json.loads(content))

1.3.3、get请求和post请求的区别

1
2
1:get请求方式的参数必须编码,参数是拼接到url后面,编码之后不需要调用encode方法
2:post请求方式的参数必须编码,参数是放在请求对象定制的方法中,编码之后需要调用encode方法

1.4、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
import urllib.request
import urllib.parse
import json

# 获取内容
def getContent(request):
return urllib.request.urlopen(request).read().decode('utf-8')

# 创建请求对象
def createRequest(page):
data = {
'type': 'movie',
'tag': '热门',
'sort': 'recommend',
'page_limit': page['pageSize'],
'page_start': page['pageNo'],
}
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.63 Safari/537.36',
}
data = urllib.parse.urlencode(data)
url = 'https://movie.douban.com/j/search_subjects?' + data
return urllib.request.Request(url=url, headers=headers)

# 将数据写入文件中
def getData(page):
file = open(file='豆瓣电影.json', mode='a', encoding='utf-8')
file.writelines(getContent(createRequest(page)))

if __name__ == '__main__':
pageNo = int(input('查询多少页:'))
pageSize = int(input('每一页查询的数量:'))

for i in range(1, pageNo + 1):
page = {'pageNo': 20,'pageSize': 20}
getData(page)

1.5、Ajax的post请求

爬取肯德基门店地区信息

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


# 返回查询内容
def getContent(request):
return urllib.request.urlopen(request).read().decode('utf-8')


# 创建请求对象
def createRequest(page):
data = {
'cname': '长沙',
'pid': '',
'pageSize': str(page['pageSize']),
'pageIndex': str(page['pageNo']),
}
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.63 Safari/537.36',
}
# post请求还需要再调用一次encode()方法
data = urllib.parse.urlencode(data).encode('utf-8')
url = 'http://www.kfc.com.cn/kfccda/ashx/GetStoreList.ashx?op=cname'
return urllib.request.Request(url=url, data=data, headers=headers)


# 将书写入文件中
def writeFile(page):
content = getContent(createRequest(page))
file = open(file='肯德基地址信息' + str(page['pageNo']) + '.json', mode='w', encoding='utf-8')
file.writelines(content)
file.close()


if __name__ == '__main__':
for i in range(1, 3):
page = {
'pageNo': i,
'pageSize': 100
}
writeFile(page)

1.6、爬虫异常

1
2
3
4
5
6
7
8
9
import urllib.error

try:
# 爬虫代码。。。。。
print('无报错')
except urllib.error.HTTPError:
print('系统正在升级。。。。')
except urllib.error.URLError:
print('系统正在升级。。。。')

1.7、cookie登录

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 使用场景:数据采集的时候,需要绕过登录,然后进入到某个页面
import urllib.request
# 请求地址
url = 'https://weibo.com/6487700506/info'
# 请求头信息
headers = {
'cookie': 'login_sid_t=2c4ccf71ca2a85cf641b07cb4fc1864a; cross_origin_proto=SSL; WBStorage=2ceabba76d81138d|undefined; _s_tentry=-; Apache=7315577089267.8955.1630663188885; SINAGLOBAL=7315577089267.8955.1630663188885; ULV=1630663188889:1:1:1:7315577089267.8955.1630663188885:; WBtopGlobal_register_version=2021090318; crossidccode=CODE-yf-1Mm60G-45S8lz-yJQsRuxArt0NwDz8b1822; SSOLoginState=1630663288; SUB=_2A25MNYIoDeRhGeBK41UW8C7JyzqIHXVv2S5grDV8PUJbkNAKLWvVkW1NR25u8iN5ciVJT-Z-RIv8CaS6M2q1bbrR; SUBP=0033WrSXqPxfM725Ws9jqgMF55529P9D9WhviuqORfY9IB4HpigCERW.5NHD95QcShnNS057SK5cWs4DqcjMi--NiK.Xi-2Ri--ciKnRi-zNSoBRS0M7eh-7Sntt; wvr=6; UOR=,,graph.qq.com; wb_view_log_6487700506=2048*12801.25; webim_unReadCount=%7B%22time%22%3A1630663744090%2C%22dm_pub_total%22%3A0%2C%22chat_group_client%22%3A0%2C%22chat_group_notice%22%3A0%2C%22allcountNum%22%3A40%2C%22msgbox%22%3A0%7D',
# 防盗链,判断当前路径是不是由上一个路径进来的,一般情况下,是做图片防盗链
'referer': 'https://account.weibo.com/',
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.63 Safari/537.36'
}
# 设置请求信息
request = urllib.request.Request(url=url, headers=headers)
# 模拟浏览器访问页面,且获取数据
content = urllib.request.urlopen(request).read().decode('utf-8')
# 将数据写入文件中
file = open(file='微博账户信息.html', mode='w', encoding='utf-8')
file.write(content)
file.close()

1.8、Handler处理器

  • 为什么要学习handler?
    • urllib.request.urlopen(url)
      • 不能定制请求头
    • urllib.request.Request(url,headers,data)
      • 可以定制请求头
    • Handler
      • 定制更高级的请求头(随着业务逻辑的复杂 请求对象的定制已经满足不了我们的需求(动态cookie和代理不能使用请求对象的定制))

handler的基本使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import urllib.request
url = 'http://www.baidu.com'
# 请求头信息
headers = {
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.63 Safari/537.36'
}
request = urllib.request.Request(url=url, headers=headers)

# handler build_opener open
# 1、获取handler对象
handler = urllib.request.HTTPHandler()
# 2、获取opener对象
opener = urllib.request.build_opener(handler)
# 3、调用open方法
response = opener.open(request)
# 4、获取数据
content = response.read().decode('utf-8')

1.9、代理服务器

  • 1.代理的常用功能?
    • 1.突破自身IP访问限制,访问国外站点。
    • 2.访问一些单位或团体内部资源
      • 扩展:某大学FTP(前提是该代理地址在该资源的允许访问范围之内),使用教育网内地址段免费代理服务 器,就可以用于对教育网开放的各类FTP下载上传,以及各类资料查询共享等服务。
    • 3.提高访问速度
      • 扩展:通常代理服务器都设置一个较大的硬盘缓冲区,当有外界的信息通过时,同时也将其保存到缓冲 区中,当其他用户再访问相同的信息时, 则直接由缓冲区中取出信息,传给用户,以提高访问速度。
    • 4.隐藏真实IP
      • 扩展:上网者也可以通过这种方法隐藏自己的IP,免受攻击。
  • 2.代码配置代理
    • 创建Reuqest对象
    • 创建ProxyHandler对象 用handler对象
    • 创建opener对象
    • 使用opener.open函数发送请求

1.9.1、单个代理

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

url = 'http://www.baidu.com/s?wd=ip'
# 请求头信息
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.63 Safari/537.36'
}
# 请求对象定制
request = urllib.request.Request(url=url, headers=headers)
# 设置代理
proxies = {
'http': '175.7.199.110:3256'
}
# handler build_open open
handler = urllib.request.ProxyHandler(proxies=proxies)
opener = urllib.request.build_opener(handler)
# # 模拟浏览器访问服务器
response = opener.open(request)
# 获取响应的信息
content = response.read().decode('utf-8')
# 保存在本地
with open('代理测试.html', 'w', encoding='utf-8')as fp:
fp.write(content)

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

url = 'http://www.baidu.com/s?wd=ip'
# 请求头信息
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.63 Safari/537.36'
}
# 请求对象定制
request = urllib.request.Request(url=url, headers=headers)
# 设置代理池
proxiesPool = [
{'http': '123.171.42.178:3256'},
{'http': '163.125.30.152:8118'},
{'http': '117.94.222.28:3256'},
{'http': '111.72.25.154:3256'},
]
# handler build_open open
handler = urllib.request.ProxyHandler(proxies=random.choice(proxiesPool))
opener = urllib.request.build_opener(handler)
# # 模拟浏览器访问服务器
response = opener.open(request)
# 获取响应的信息
content = response.read().decode('utf-8')
# 保存在本地
with open('代理测试.html', 'w', encoding='utf-8')as fp:
fp.write(content)

2、解析

2.1、xpath

1
2
3
4
5
6
7
8
9
1.安装lxml库
pip install lxml -i https://pypi.douban.com/simple
2.导入lxml.etree
from lxml import etree
3.etree.parse() 解析本地文件
html_tree = etree.parse('XX.html')
4.etree.HTML() 服务器响应文件
html_tree = etree.HTML(response.read().decode('utf‐8')
4.html_tree.xpath(xpath路径)

2.1.1、xpath安装

  1. 在谷歌商店中安装xpath插件
  2. 安装lxml到python的Scripts的文件夹中【pip install lxml】

2.1.2、xpath基本语法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
xpath基本语法:
1.路径查询
//:查找所有子孙节点,不考虑层级关系
/ :找直接子节点
2.谓词查询
//div[@id]
//div[@id="maincontent"]
3.属性查询,class,value,自定义属性
//@class
//@value

4.模糊查询
//div[contains(@id, "he")]
//div[starts‐with(@id, "he")]
5.内容查询
//div/h1/text()
6.逻辑运算
//div[@id="head" and @class="s_down"]
//div[@id="head"] | //div[@id="bottom"]

解析本地文件

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
from lxml import etree

# 1、本地文件 etree.parse
# 2、服务器响应的数据(response.read().decode('utf-8') etree.HTML()

# xpath解析本地文件
tree = etree.parse('1、xpath的基本使用.html')

# 路径查询:查找ul下的li。text()获取标签中的内容
lis = tree.xpath('//body/ul/li')

# 谓词查询:查询指定标签,且包含id的标签的内容,text():查看查看标签中的内容
liHasId = tree.xpath('//ul/li[@id]/text()')
print(liHasId)

# 谓词查询:根据id查找指定标签中的文本值,注意引号
liIdIsLi1 = tree.xpath('//ul/li[@id="li1"]/text()')
print(liIdIsLi1)

# 属性查询:根据指定id查找该id下面的查找指定标签的class的值
liClassValue = tree.xpath('//ul/li[@id="li1"]/@class')
print(liClassValue)

# 模糊查询:查询指定标签的id值中含有指定字符的内容
liCon = tree.xpath('//ul/li[contains(@id,"l")]/text()')
print(liCon)

# 模糊查询:判断id以谁开头的内容
idStartWith = tree.xpath('//ul/li[starts-with(@id,"a")]/text()')
print(idStartWith)

# 逻辑运算:查询id和class的值为指定值的内容
liByIdAndClass = tree.xpath('//ul/li[@id="li1" and @class="classValue"]/text()')
print(liByIdAndClass)

# 逻辑运算:查询id或class的值为指定值的内容
liByIdOrClass = tree.xpath('//ul/li[@id="li1"]/text() | //ul/li[@id="li2"]/text()')
print(liByIdOrClass)

解析服务器响应的数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 1、获取网页的源码
# 2、解析,解析的服务器响应的文件 etree.HTML
# 3、打印
import urllib.request
from lxml import etree

url = 'https://www.baidu.com'
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.63 Safari/537.36'
}
# 请求对象定制
request = urllib.request.Request(url=url, headers=headers)
# 模拟浏览器访问服务器
response = urllib.request.urlopen(request)
# 获取网页源码
content = response.read().decode('utf-8')
# 解析网页源码,来获取想要的数据,解析服务器响应的文件
tree = etree.HTML(content)
# 获取想要的数据
result = tree.xpath('//input[@id="su"]/@value')[0]
print(result)

2.1.3、xpath基本使用

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

# 1、请求对象定制
# 2、获取网页的源码
# 3、下载

# 1、请求对象定制
def createRequest(pageNo):
url = ""
if pageNo == 1:
url = 'https://sc.chinaz.com/tupian/meinvtupian.html'
elif pageNo > 1:
url = 'https://sc.chinaz.com/tupian/meinvtupian_' + str(pageNo) + '.html'
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.63 Safari/537.36'
}
return urllib.request.Request(url=url, headers=headers)


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


# 3、下载
def dowImage(content):
# 根据xpath语法解析数据
tree = etree.HTML(content)
titles = tree.xpath('//div[@id="container"]//a/img/@alt')
srcs = tree.xpath('//div[@id="container"]//a/img/@src2')
items = []
for i in range(0, len(titles)):
items.append({'title': titles[i], 'src': "https" + srcs[i]})
for item in items:
print(item)


if __name__ == '__main__':
pageNo = int(input('起始页:'))
endPage = int(input('结束页:'))
for page in range(pageNo, endPage + 1):
# 1、请求对象的定制
request = createRequest(page)
# 2、获取网页源码
content = getContent(request)
# 下载
dowImage(content)

2.2、jsonpath

jsonpath安装

1
pip install jsonpath

jsonpath的基本使用

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

url = 'https://dianying.taobao.com/cityAction.json?activityId&_ksTS=1630931434381_141&jsoncallback=jsonp142&action=cityAction&n_s=new&event_submit_doGetAllRegion=true'
headers = {
'accept': 'text/javascript, application/javascript, application/ecmascript, application/x-ecmascript, */*; q=0.01',
'accept-language': 'zh-CN,zh;q=0.9',
'cookie': 't=719b007b3e7950d336a784bd7b946cc2; td_cookie=1310130070; cookie2=100b92bae0ce9a1a6910e6580c48328a; v=0; _tb_token_=33661457eb3ed; cna=Ng62GZoZwzACAd+YhpEubw0x; xlly_s=1; tfstk=c9GlBQ4CFYyWTR2mCQNSzU6HSppOZf7zfXkEgXKLJTKjgqhVitWVQj86oPno991..; l=eBjfLLvmgM2_tx-XBO5aourza77TBIRb4sPzaNbMiInca6GltF_AvNCKz2qkSdtjgtCffetP_1j3WdLHR3xg5c0c07kqm0Jn3xvO.; isg=BFRUAfoQyTFjK119l_936Tp6JZLGrXiXTdCAjO41GV9i2fQjFr-VJ0xX2dHBIbDv',
'referer': 'https://dianying.taobao.com/',
'sec-ch-ua': '"Google Chrome";v="93", " Not;A Brand";v="99", "Chromium";v="93"',
'sec-ch-ua-mobile': '?0',
'sec-ch-ua-platform': '"Windows"',
'sec-fetch-dest': 'empty',
'sec-fetch-mode': 'cors',
'sec-fetch-site': 'same-origin',
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.63 Safari/537.36',
'x-requested-with': 'XMLHttpRequest'
}
request = urllib.request.Request(url=url, headers=headers)
response = urllib.request.urlopen(request)
content = response.read().decode('utf-8')
content = content.split('(')[1].split(')')[0]
file = open('2、jsonpath解析淘票票.json', 'w', encoding='utf-8')
file.write(content)
file.close()

obj = json.load(open('2、jsonpath解析淘票票.json', 'r', encoding='utf-8'))
name = jsonpath.jsonpath(obj, '$.returnValue.A[0].regionName')
print(name)

2.3、.BeautifulSoup

2.3.1、安装及简介

基本简介

  • BeautifulSoup简称: bs4
  • 什么是BeatifulSoup?
    • BeautifulSoup,和lxml一样,是一个html的解析器,主要功能也是解析和提取数据
  • 优缺点?
    • 缺点:效率没有lxml的效率高
    • 优点:接口设计人性化,使用方便

安装及其创建

  • 安装
    • pip install bs4
  • 导入
    • from bs4 import BeautifulSoup
  • 创建对象
    • 服务器响应的文件生成对象
      • soup = BeautifulSoup(response.read().decode(), ‘lxml’)
    • 本地文件生成对象
      • soup = BeautifulSoup(open(‘1.html’), ‘lxml’)
      • 注意:默认打开文件的编码格式gbk所以需要指定打开编码格式

2.3.2、bs4的基本使用

格式:

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
1.根据标签名查找节点
soup.a 【注】只能找到第一个a
soup.a.name
soup.a.attrs
2.函数
(1).find(返回一个对象)
find('a'):只找到第一个a标签
find('a', title='名字')
find('a', class_='名字')
(2).find_all(返回一个列表)
find_all('a') 查找到所有的a
find_all(['a', 'span']) 返回所有的a和span
find_all('a', limit=2) 只找前两个a
(3).select(根据选择器得到节点对象)【推荐】
1.element
eg:p
2..class
eg:.firstname
3.#id
eg:#firstname
4.属性选择器
[attribute]
eg:li = soup.select('li[class]')
[attribute=value]
eg:li = soup.select('li[class="hengheng1"]')
5.层级选择器
element element
div p
element>element
div>p
element,element
div,p
eg:soup = soup.select('a,span')

示例

1
2
3
4
5
6
<ul>
<li><a href="#" title="测试" class="aaa">测试</a></li>
<li><a href="21321" title="测试2" class="bbb">测试2</a></li>
<li><a href="#"><span>测试一下</span></a></li>
<li><a href="##" id="ccc"></a></li>
</ul>
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
from bs4 import BeautifulSoup

# 通过解析本地文件,来将bs4的基础语法进行解析
soup = BeautifulSoup(open('1、bs4的基本使用.html', 'r', encoding='utf-8'), 'lxml')

# 根据标签名查找节点

# 查找第一个符合条件的数据
print(soup.a)
# 获取标签的属性和属性值
print(soup.a.attrs)

# bs4的一些函数
# find find_all select

# find:返回的是第一个符合条件的数据
print(soup.find('a'))
print(soup.find('a', title='测试2')) # 根据属性的值来查找数据
print(soup.find('a', class_='aaa')) # 根据class的值来找到对应的标签对象。注意:class要写成class_

# find_all:返回所有满足条件的数据,返回一个列表
print(soup.find_all('a'))
print(soup.find_all('a', class_='bbb'))
# 想要获取多个标签的数据,需要在find_all的参数中添加的是列表的数据
print(soup.find_all(['a', 'span']))
print(soup.find_all('li', limit=1)) # limit:用于指定查找前几个的数据

# select(推荐):返回的是一个列表,并且返回多个数据
print("=====================select=========================")
print(soup.select('a'))
print(soup.select('a[class="aaa"]')) # 根据class选择器来选中

2.3.3、节点信息-获取标签内容

基本使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
from bs4 import BeautifulSoup

soup = BeautifulSoup(open('1、bs4的基本使用.html', 'r', encoding='utf-8'), 'lxml')
obj = soup.select('#div1')[0]

1、获取节点内容:适用于标签中嵌套标签的结构
obj.string
obj.get_text()【推荐】
2、节点的属性
tag.name 获取标签名
eg:tag = find('li')
print(tag.name) # 输出:li
tag.attrs将属性值作为一个字典返回【属性名:属性值】
3、获取节点属性:因为obj.attrs返回一个字典,可以直接使用字典的方法le
obj.attrs.get('title')【常用】
obj.get('title')
obj['title']

示例

1
<div id="div1"><span>测试一下</span></div>
1
2
3
4
5
6
7
8
9
10
11
12
13
from bs4 import BeautifulSoup

# 通过解析本地文件,来将bs4的基础语法进行解析
soup = BeautifulSoup(open('1、bs4的基本使用.html', 'r', encoding='utf-8'), 'lxml')

# 节点信息,获取节点内容
# 如果标签对象中,除了内容还有标签,那么string就获取不到数据,而get_text()是可以获取数据
# 一般情况下,推荐使用get_text()
textValue = soup.select('#div1')[0]
print(textValue.value) # None
print(textValue.get_text()) # 测试一下
print(textValue.attrs) # {'id': 'div1'}
print(textValue.attrs.get('id')) # div1

使用bs4获取星巴克数据

1
2
3
4
5
6
7
8
9
10
11
12
13
import urllib.request
from bs4 import BeautifulSoup

url = 'https://www.starbucks.com.cn/menu/'
response = urllib.request.urlopen(url=url)
content = response.read().decode('utf-8')

soup = BeautifulSoup(content, 'lxml')

names = soup.select('ul[class="grid padded-3 product"] strong')

for name in names:
print(name.get_text().replace('™', ''))

3、Selenium

3.1、selenium

3.1.1、Seleneum基本使用

  1. 什么是selenium是一个用于web程序
    • Selenium是一个用于Web应用程序测试的工具。
    • Selenium 测试直接运行在浏览器中,就像真正的用户在操作一样。
    • 支持通过各种driver(FirfoxDriver,IternetExplorerDriver,OperaDriver,ChromeDriver)驱动 真实浏览器完成测试。
    • selenium也是支持无界面浏览器操作的
  2. 为什么使用selenium?
    • 模拟浏览器功能,自动执行网页中的js代码,实现动态加载
  3. 如何安装selenium?
  4. selenium的使用步骤?
    • 导入:from selenium import webdriver
    • 创建谷歌浏览器操作对象: path = 谷歌浏览器驱动文件路径 browser = webdriver.Chrome(path)
    • 访问网址 url = 要访问的网址 browser.get(url)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 1、导入selenium
from selenium import webdriver

# 2、创建浏览器操作对象
path = 'chromedriver.exe' # 浏览器驱动的路径
browser = webdriver.Chrome(path)

# 3、访问网址
url = 'https://www.jd.com/'
browser.get(url)

# page_source获取网页源码
content = browser.page_source
print(content)

3.1.2、Selenium元素定位

api

1
2
3
4
5
6
7
8
9
10
11
12
1.find_element_by_id #【根据id查询】
eg:button = browser.find_element_by_id('su')
2.find_elements_by_name # 根据name属性的值
eg:name = browser.find_element_by_name('wd')
3.find_elements_by_xpath # 根据xpath语法
eg:xpath1 = browser.find_elements_by_xpath('//input[@id="su"]')
4.find_elements_by_tag_name # 根据标签名字
eg:names = browser.find_elements_by_tag_name('input')
5.find_elements_by_css_selector # 根据css选择器
eg:my_input = browser.find_elements_by_css_selector('#kw')[0]
6.find_elements_by_link_text # 根据连接文本
eg:browser.find_element_by_link_text("新闻")

示例

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
from selenium import webdriver

path = 'chromedriver.exe'
browser = webdriver.Chrome(path)

url = 'https://www.baidu.com/'
browser.get(url)

# 元素定位

# find_element_by_id
respById = browser.find_element_by_id('su')

# 根据标签属性的属性值来获取对象,根据name属性的值来获取对象
respByName = browser.find_element_by_name('wd')

# 根据xpath语句来获取对象
respByXpath = browser.find_element_by_xpath('//input[@id="su"]')

# 根据标签名来获取对象
respByTagName = browser.find_elements_by_tag_name('input')

# 使用css选择器
respByCss = browser.find_element_by_css_selector('#su')

# 根据连接文本的值来获取标签,比如:a标签就是连接文本
respByLink = browser.find_element_by_link_text('地图')

3.1.3、selenium访问元素信息

方法

1
2
3
获取元素信息:【 .get_attribute 】
获取标签之间的文本信息:【 .text 】
获取标签的名字:【 .tag_name 】

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
from selenium import webdriver

path = 'chromedriver.exe'
browser = webdriver.Chrome(path)

url = 'https://www.baidu.com/'
browser.get(url)

respById = browser.find_element_by_id('su')
print(respById.get_attribute('class')) # 获取指定属性的值
print(respById.tag_name) # 获取标签名字
print(respById.text) # 获取标签之间的文本信息
print(respById.get_attribute('value')) # 获取双标签之间的文本

3.1.4、selenium交互

selenium交互就是模拟用户操作浏览器,点击按钮,上一页,往文本框中输入信息等操作

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
from selenium import webdriver
import time

path = 'chromedriver.exe'
browser = webdriver.Chrome(path)
url = 'https://www.baidu.com/'

browser.get(url)

time.sleep(2) # 睡眠两秒
respById = browser.find_element_by_id('kw') # 获取文本框的对象
respById.send_keys('周杰伦') # 文本框中输入周杰伦
time.sleep(2) # 睡眠两秒
respByIdBtn = browser.find_element_by_id('su') # 点击百度一下
respByIdBtn.click() # 点击按钮
time.sleep(2) # 睡眠两秒
toBottom = 'document.documentElement.scrollTop=100000' # 滑到底部
browser.execute_script(toBottom) # 滑到底部
time.sleep(2) # 睡眠两秒
nextBtn = browser.find_element_by_xpath('//a[@class="n"]') # 获取下一页按钮
nextBtn.click() # 点击下一页
time.sleep(2) # 睡眠两秒
browser.back() # 回到上一页
time.sleep(2) # 睡眠两秒
browser.forward() # 回到之前页面
browser.quit() # 退出

3.2、Phantomjs

下载

https://phantomjs.org/download.html

使用

1
2
3
4
5
6
7
8
from selenium import webdriver

path = 'phantomjs.exe'
browser = webdriver.PhantomJS(path)

url = 'https://www.baidu.com/'
browser.get(url)
browser.save_screenshot('百度首页截图.webp') # 截图

3.3、Chrome handless

Chrome-headless 模式, Google 针对 Chrome 浏览器 59版 新增加的一种模式,可以让你不打开UI界面的情况下 使用 Chrome 浏览器,所以运行效果与 Chrome 保持完美一致。

系统要求

1
2
3
4
5
6
7
1.系统要求:
Chrome
Unix\Linux 系统需要 chrome >= 59
Windows 系统需要 chrome >= 60
Python3.6
Selenium==3.4.*
ChromeDriver==2.31

配置和使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
from selenium import webdriver
from selenium.webdriver.chrome.options import Options


# 封装的handlers
def shareBrowser():
chrome_options = Options()
chrome_options.add_argument('--headless')
chrome_options.add_argument('--disable‐gpu')

path = r'C:\Program Files\Google\Chrome\Application\chrome.exe'
chrome_options.binary_location = path

browser = webdriver.Chrome(options=chrome_options)
return browser


browser = shareBrowser()
url = 'https://www.baidu.com/'
browser.get(url)
browser.save_screenshot('百度首页.webp')

4、requests

4.1、基本使用

文档

官网:https://docs.python-requests.org/zh_CN/latest/

快速上手:https://docs.python-requests.org/zh_CN/latest/user/quickstart.html

安装

1
pip install requests

responses基本属性

1
2
3
4
5
6
7
8
3.response的属性以及类型
类型 :models.Response
r.text :获取网站源码
r.encoding :访问或定制编码方式
r.url :获取请求的url
r.content :响应的字节类型
r.status_code :响应的状态码
r.headers :响应的头信息

使用【一个类型和六个方法】

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

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

# 一个类型和六个属性
response = requests.get(url=url)
print(type(response)) # 一个类型
response.encoding = 'utf-8' # 属性:访问或定制编码方式
print(response.url) # 属性:获取请求的url
print(response.content) # 属性:响应的字节类型
print(response.status_code) # 属性:响应的状态码
print(response.text) # 属性:获取网站源码
print(response.headers) # 属性:响应的头信息

4.2、requests-get请求

urllib和requests对比

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# urllib
# (1) 一个类型以及六个方法
# (2)get请求
# (3)post请求 百度翻译
# (4)ajax的get请求
# (5)ajax的post请求
# (6)cookie登陆 微博
# (7)代理


# requests
# (1)一个类型以及六个属性
# (2)get请求
# (3)post请求
# (4)代理
# (5)cookie 验证码

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

url = 'https://www.baidu.com/s'

headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36'
}

data = {
'wd': '北京'
}

# url 请求资源路径
# params 参数
# kwargs 字典
response = requests.get(url=url, params=data, headers=headers)
content = response.text
print(content)

# 总结:
# (1)参数使用params传递
# (2)参数无需urlencode编码
# (3)不需要请求对象的定制
# (4)请求资源路径中的?可以加也可以不加

4.3、requests-post请求

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

url = 'https://fanyi.baidu.com/sug'

headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36'
}

data = {
'kw': 'eye'
}

# url 请求地址
# data 请求参数
# kwargs 字典
response = requests.post(url=url, data=data, headers=headers)

content = response.text

obj = json.loads(content)
print(obj)

# 总结:
# (1)post请求 是不需要编解码
# (2)post请求的参数是data
# (3)不需要请求对象的定制

4.4、代理

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

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

headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36',
}

data = {
'wd': 'ip'
}

proxy = {
'http': '183.240.203.136:8118'
}

response = requests.get(url=url, params=data, headers=headers, proxies=proxy)

content = response.text

with open('代理.html', 'w', encoding='utf-8')as fp:
fp.write(content)

5、scrapy

5.1、scrapy

5.1.1、scrapy简介

1
2
3
4
5
6
7
1、scrapy是什么?
scrapy是为了一个爬取网页数据,提取结构性数据而编写的应用框架,可以应用在包括数据挖掘,信息处理或存储历史数据等一系列的程序中

2、安装scrapy
pip install scrapy

安装出错,自行百度

5.1.2、scrapy项目的创建及运行

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
1、scrapy创建项目
终端输入:scrapy startproject 项目名称 【例如:scrapy startproject baidu-project】

2、项目组成:
spiders
__init__.py
自定义爬虫文件.py ----> 自己创建、编写的爬虫文件
__init__.py
items.py ---->定义数据结构的地方 ,是一个集成scrapy.Item的类
middlewares.py ---->中间件 代理
pipelines.py ---->管道文件,里面只有一个类,用于处理下载的后续处理,默认是300优先级,值越小优先级越高(1-1000
settings.py ---->配置文件,比如:是否遵守robots协议,User-Agent定义等

3、创建爬虫文件
1)进入到spiders文件夹
2)scrapy genspider 爬虫文件的名字 要爬取网页【例如:scrapy genspider baidu www.baidu.com】

4、爬虫文件的基本组成
集成scrapy.spider类
name='baidu' # 爬虫的名字,用于运行爬虫的时候使用的值
allowed_domains = ['www.baidu.com'] # 允许访问的域名,在爬取的时候,如果不是在此域名之下的url,会被过滤掉
start_urls = ['http://www.baidu.com/'] # 声明了爬虫的起始地址。可以写多个url,一般是一个
def parse(self, response): # 解析数据的回调函数
response.txt # 响应的字符串
response.body # 响应的是二进制文件
response.xpath() # xpath方法的返回值类型是selector列表
extract() # 提取的是selector对象的是data
extract_first() # 提取的是selector列表中的第一个数据

5、scrapy文件运行
scrapy crawl 文件名称【例如:在spiders文件夹中编写的python文件'get_baidu.py',运行:scrapy crawl get_baidu】
注意:应放在spiders文件夹内部执行

5.1.3、scrapy架构组成

1
2
3
4
5
6
7
8
9
10
1、引擎						----->自动运行,无需关注
2、下载器 ---->从引擎处获取到请求对象后,请求数据
3、spiders ----->spider类定义了如何爬取某个(或某些)网站,包括了爬取的动作(例如:是否跟进链接)以及如何从网页的内容中提取结构化数据(爬取item)。换句话说,spider就是定义爬取的动作及分析某个网页(或有些网页)的地方。
4、调度器 ---->有自己的调度规则,无需关注
5、管道(Item pipeline) ---->最终处理数据的管道,会预留接口供我们处理数据。当Item在Spider中被收集之后,它将会被传递到Item pipeline,一些组件会按照一定的执行顺序执行对Item的处理,每个Item pipeline(有时称之为”Item pipeline“)是实现了简单方法的python类,他们接收到Item并通过它执行一些行为,同时也决定此Item是否创建通过pipeline,或是被丢弃而不再进行处理
以下是item pipeline的一些典型应用:
清理HTML数据
验证爬取的数据(检查Item包含某些字段)
查重(并丢弃)
将爬取结果保存到数据库中

5.1.4、scrapy工作原理

image-20210908202558151

image-20210908202725951

5.2、scrapy shell

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
1、什么是scrapy shell?
scrapy终端,是一个交互终端,可以在未启动spider的情况下尝试及调试爬取代码,其本意是用来测试提取数据的代码。不过,可以将其视作为正常的python终端,在上面测试任何python代码
该终端是用来测试xpath
或css表达式,查看他们的工作方式及从爬取的网页中提取的数据。在编写spider时,该终端提供了交互性测试的表达式代码的功能,免去了每次修改后运行spider的麻烦

2、安装ipython
安装:pip install ipython
简介:如果安装了ipython,scrapy终端将使用ipython(替代标准python终端)。ipython终端与其他相比,更强大,提供了代码自动补全,高亮等其他功能

3、应用
scrapy shell www.baidu.com
scrapy shell http://www.baidu.com
scrapy shell "http://www.baidu.com"
scrapy shell "www.baidu.com"

4、语法
(1)response对象:
response.body、response.text、response.url、response.status
(2)response的解析:
response.xpath() # 常用
使用xpath路径查询特定元素,返回一个selector列表对象
response.css()
使用css_selector查询元素,返回一个selector列表对象
获取内容:response.css('#su::text').extract_first()
获取属性:response.css('#su::attr("value")').extrace_first()
extract_first()
提取selector列表中的第一个值
如果提取不到值,会返回一个空值
返回第一个解析到的值,如果列表为空,此方法不会报错,会返回一个空值
xpath()
css()
注意:每一个selector对象可以再次的去使用xpath或css方法

5.3、yield

  • 带有yield的函数不再是一个普通函数,而是一个生成器generator,可用于迭代
  • yield是一个类似return的关键字,迭代一次遇到yield时就返回yield后面(右边)的值。重点是:下一次迭代时,从上一次迭代遇到的yield后面的代码(下一行)开始执行
  • 简单理解:yield就是return返回一个值,并且记住这个返回值的位置,下次迭代就是从这个位置后(下一次)开始

案例:

  • 当当网:(1)yield (2) 管道封装 (3)多条管道下载 (4) 多页数据下载
  • 电影天堂 (1) 一个item包含多级页面的数据

5.4、

5.5、MySQL和pymysql安装和使用

MySQL安装

自行百度查询

pymysql安装和使用

pymysql是一个连接mysql的工具

1
2
3
4
5
6
7
# 安装
pip install pymysql

# 连接使用
conn = pymysql.connect(host,port,user,password,db,charset)
cursor = conn.cursor()
cursor.executer()

5.4、当当网

5.5、电影天堂