爬虫基础阶段
大纲
请求与相应
http协议相关
数据解析
代理、验证码、cookie等
相关的反爬技能
数据库
Playwright
三方抓包 工具
重要数据类型
列表数据类型(数据结构)
-
在实际开发中,经常需要将一组(不止一个)数据存储起来,以便后边的代码使用。列表就是这样的一个数据结构。且列表是Python中最基本也是最常用的数据结构 之一
-
什么是数据结构?
- 通俗来讲,可以将数据结构当作是某种容器,该容器是用来装载或者存储数据的。不同的数据结构决定了对数据不同的组织方式。
- 那么当数据被装载或者存储到了某个数据结构中后,那么就可以基于该数据结构的特性对数据进行不同形式的处理和运算
-
列表的创建方式
- 创建一个列表,只要把逗号分隔的不同的数据元素使用方括号括起来即可。列表内的元素,可以是其他任意类型的数据,可以多层嵌套列表,元素个数无限制。
alist = [1,2,3,4,5] items = [1,'bobo',12.34] #列表中可以存储任意类型的数据
-
列表元素
- 存储在列表数据结构中的每一个数据被称为列表元素,简称元素
-
列表索引(类似于c语言的数组)
- 列表中的每个元素都被分配一个数字作为索引,用来表示该元素在列表内所排在的位置。第一个元素的索引是0,第二个索引是1,以此类推。
-
访问列表内的元素
- 列表从0开始为它的每一个元素顺序创建下标索引,直到总长度减一。要访问它的某个元素,以方括号加下标值的方式即可。注意要确保索引不越界,一旦访问的索引超过范文,会抛出异常。所以,一定要记得最后一个元素的索引是len(list)-1。
alist = [1,12.3,'bobo'] print(alist[2]) #'bobo' print(alist[0:2]) #[1,12] print(alist[6]) #使用索引和切片的时候,不可以访问超出索引范围的元素
-
修改元素的值
- 直接对元素进行重新赋值
alist = [1,12.3,'bobo'] alist[1] = 100.123 print(alist)
-
删除元素
- 使用del语句或者remove(),pop()方法删除指定的元素。
alist = [1,12.3,'bobo']
-
切片
-
切片指的是对序列进行截取,选取序列中的某一段
-
切片的语法是: list[start:end]
#同字符串的切片机制一样 alist = [1,12.3,'bobo','jay','hello'] print(alist[:-1])
-
以冒号分割索引,start代表起点索引,end代表结束点索引。省略start表示以0开始,省略start表示以0开始,省略end表示到列表的结尾。注意,区间是左闭右开!也就是说[1:4]会截取列表的索引为1/2/3的3个元素,不会截取索引为4的元素。分片不会修改原有的列表,可以将结果保存到新的变量,因此切片也是一种安全操作,常被用来复制一个列表,例如newlist = lis[:]。
-
切片过程中还可以设置步长,以第二个冒号分隔,例如list[3:9:2],表示每隔多少距离取一个元素。
-
-
列表的内置方法
-
上文中我们说过,数据存储到不同的数据结构中,可以基于该数据结构的特性对数据进行指定形式的操作和处理。下图中的方法是列表专有的内置方法,请熟记于心。
-
作用 方法 append() 在列表末尾添加新的对象 count() 统计某个元素在列表中出现的次数 extend() 在列表末尾一次性追加另一个序列中的多个值 index() 从列表中找出某个值第一个匹配项的索引位置 insert() 将对象插入列表 pop() 移除列表中的一个元素(默认最后一个),并且返回该元素的值 remove() 移除列表中某个值的第一个匹配项 reverse() 反向列表中的元素 sort() 对原列表进行排序 copy() 复制列表 clear() 清空列表,等于del list[:]
alist = ['bobo',"18","99.5",'北京'] #将列表转换成字符串 ret = '-'.join(alist) #将列表中的每个列表元素根据-为间隔进行拼接,返回字符串结果 print(ret) #如何将字符串转化为列表 s = 'hello-name-bobo-age' ret = s.split('-') print(ret) alist = [3,8,5,7,6,2,1] alist.sort() #对列表元素进行排序 print(alist) a = [1,2,3] a.append('bobo') #向列表尾部添加一个元素 print(a) a1 = [1,2,3] a1.insert(1,999) #向列表下标为1的位置添加一个元素 print(a1)
-
字典数据类型
-
字典的实现机制:
- Python的字典数据类型是基于hash散列算法实现的,采用键值对(key:value)的形式,根据key的值计算value的地址,具有非常快的查询和插入速度。
-
字典特性:
- 字典包含的元素个数不限,值的类型可以是任何数据类型,采用键值对(key:value)的形式,根据key的值计算value的地址,具有非常快的查询和插入速度
-
字典特性:
- 字典包含的元素个数不限,值的类型可以是任何数据类型!但是字典的key必须是不可变的对象,例如整数、字符串、bytes和元组,最常见的还是将字符串作为key。列表、字典、集合等就不可以作为key。同时,同一个字典内的key必须是唯一的(基于哈希),但值则不必。
- 注意:从Python3.6开始,字典是有序的!它将保持元素插入时的先后顺序,务必注意!
-
创建字典
-
字典的每个键值对用冒号(:)分割,每个键值对之间用逗号(,)分隔,整个字典包括在花括号({})中,例如:
-
d = {key1:value1,key2:value2}
#键值对: key:value #key:只能使用不可变类型的数据充当,通常使用字符串 #value: 任意数据类型的值充当 #字典中无法存储重复的键值对 dict_1 = {'name':'bobo','age':'18','score':'100','age':'18'} #注意:不要在字段中存储相同的key,value可以相同 dict_2 = {'name':'bobo','age':18,'age':20} print(dict_2)
-
-
访问字典
- 虽然现在的字典在访问时有序了,但字典依然是集合类型,部署序列类型,因此没有索引下标的概念,更没有切片的说法。但与list类似的地方是,字典采用把相应的键放入方括号内获取对应值的方式取值。
d = {'name':'bobo','age':18,'scrores':[100,220,99]} #根据key访问对应的value值 print(d['name'],d['scores']) #依次访问name和scores对应的值 print(d.get('name')) #通过get使用对应的key访问对应的value值 #注意:使用[]访问不存在的key对应的value值程序会报错 # print(d['address']) #程序报错 # 注意:使用get访问不存在的key程序不会报错,但是会返回None这个空值 print(d.get('address'))
-
添加和修改
- 增加就是往字典插入新的键值对,修改就是给原有的键赋予新的值。由于一个key只能对应一个值,所以,多次对一个key赋值,后面说的值会把前面的值覆盖掉。
d = {'name':'bobo','age':20,"scores":[100,200,99]} d['name'] = 'jay' #给存在的key修改对应的value值 d['address'] = 'BeiJing' #给一个不存在的值赋值表示新增键值对 del d['age'] #删除age键值对 print(d)
-
删除字典元素、清空字典元素、清空字典和删除字典
- 使用del关键字删除字典元素或者字典本身,使用字典的clear()方法清空字典。
d = {'name':'bobo','age':'20',"scores":[100,120,99].'name':'bobo'} del d['name'] print(d) d = {'name':'bobo','age':20,"scores":[100,120,99],'name':'bobo'} del d print(d) d = {'name':'bobo','age':20,"scores":[100,120,99],'name':'bobo'} d.clear() print(d)
-
字典的重要方法
d = {'name':'bobo','age':20,"scores":[100,120,99],'name':'bobo'} print(d.key()) #返回字典中所有的key print(d.values()) #返回字典中所有的value print(d.items()) #返回字典中所有的键值对
练习
-
写一个程序,输出100以内的所有偶数,直到累加和大于1000.
#写一个程序,输出100以内的所有偶数,直到累加和大于1000. suam = 0 for i in range(101): if i % 2 == 0: if suam >= 1000: break suam += i #print(i) print(suam)
-
已知a+b+c =1000且a^2+b^2=c^2(a,b,c都是自然数),求出符合条件的a,b,c的所有组合。
#已知a+b+c =1000且a^2+b^2=c^2(a,b,c都是自然数),求出符合条件的a,b,c的所有组合。 for a in range(1001): for b in range(1001): c = 1000 - a - b if a + b + c == 1000 and a**2 + b**2 == c**2: print(a, b, c)
-
给定一个字符串test = "Hello World!",请统计字符串中每个字符的出现次数,并将结果存储在一个字典中。
text = "hello world" tongji = {} for i in text: if i not in tongji: tongji[i] = 1 else: tongji[i] += 1 print(tongji)
-
猜数字游戏设计: 可以不间断的进行猜数字游戏环境,找到猜对了,结束程序,猜不对,可有不断的进行游戏,并且需要提示用户猜大了还是猜小了。
-
最后需要统计出,用户猜了多少次猜对。
-
每一个用户的初始分数为100,每猜错一次扣5分,最后程序结束,统计用户的得分
import random guess_num = random.randint(1,10) count = 0 score = 100 while 1: count += 1 # 让用户输入数字 num = int(input('输入一个数字:')) # 判断num和guess_num是否一样 if num == guess_num: print('猜对了') break elif num < guess_num: print('猜小了') score -= 5 else: print('猜大了') score -= 5 print('一共猜的次数:',count) print('最后得分:',score)
import random guess_num = random.randint(1,10) count = 0 score = 100 while 1: count += 1 # 让用户输入数字 num = int(input('输入一个数字:')) # 判断num和guess_num是否一样 if num == guess_num: print('猜对了') break elif num < guess_num: print('猜小了') score -= 5 else: print('猜大了') score -= 5 print('一共猜的次数:',count) print('最后得分:',score)
-
文件操作
文件打开
-
Python内置了一个open()方法,用于对文件进行读写操作。使用open()方法操作文件就像把大象塞进冰箱一样,可以分三步走,一是打开文件,二是操作文件,三是关闭文件
-
文件句柄/文件描述符
-
open()方法的返回值是一个file对象,可以将他赋值给一个变量,这个变量就是所谓的文件句柄。
-
file对象:
-
可以调用read()和write()方法,对打开的文件进行读写操作
-
-
open方法的语法
- f = open(filename,mode)
- filename:
- 一个包含了你要访问的文件名称的字符串值,通常是一个文件路径
- 文件路径作用:有很多种,默认是只读方式r
- mode:
- 打开文件的模式,有很多种,默认是只读方式r
-
打开文件的模式:
-
常规文件打开模式操作演示
- b模式:
- 二进制模式,通常用来读取图片、视频等二进制文件。注意,它在读写的时候是以bytes类型读写的,因此获得的是一个bytes对象而不是字符串。在这个读写过程中,需要自己指定编码格式。在使用带b的模式时,一定要注意传入的数据类型,确保为bytes类型。
- +模式:
- 对于w+模式,在读写之前都会清空文件的内容。
- 对于a+模式,永远只能在文件的末尾写入。
- 对于r+模式,也就是读写模式
-
编码问题
- 要读取非UTF-8编码的文件,需要给open()函数传入encoding函数,例如,读取GBK编码的文件
- 遇到有些编码不规范的文件,可能会抛出UnicodeDecodeError异常,这这表示在文件中可能夹杂了一些非法编码的字符。遇到这种情况,可以提供error='ignore'参数,表示如果遇到编码错误后如何处置。
文件对象操作
-
每当我们用open方法打开一个文件时,将返回一个文件对象,这个对象内置了很多操作方法。
-
f.read(size) #size读取数据的个数
- 读取 一定大小的数据,然后 作为字符串或字节对象返回。size是一个可选的数字类型的参数,用于指定读取的数据量。当size被忽略了或者为负值,那么该文件的所有内容都将被读取并且返回。
- 注意:
- 如果文件体积较大,请不要使用read()方法一次性读入内存,而是read(512)这种一点一点的读。
-
f.readline()
- 从文件中读取一行n内容。换行符为"\n"。如果返回一个空字符串,说明已经读取到最后一行。这种方法,通常是读一行,处理一行,并且不能回头,只能前进,读过的行不能再读了。
-
f.readlines()
- 将文件中所有的行,一行一样全部读入一个列表内,按顺序一个一个作为列表的元素,并返回这个列表。readlines方法会一次性将文件全部读入内存,所以也存在一定的风险。但是它有一个好处,每行都保存在列表里,可以随意存取。
#需求:读取文件中的数据 fp = open('./test.txt','r') text = fp.read(10) #读取指定字节的数据 text_line = fp.readline() #一次读取一行数据 text_lines = fp.readlines() #读取多行数据,返回一个列表 print(text_lines) fp.close()
-
总结:
- 几种不同的读取和遍历文件的方法比较:如果文件很小,read()一次性读取最方便;如果不能确定文件大小,反复调用read(size)比较保险;如果时配置文件,调用readlines()最方便。普通情况,使用for循环更好,速度更快。
-
f.write()
- 将字符串或bytes类型的数据写入文件内。write()动作可以多次重复进行,其实都是在内存中的操作,并不会立刻写回硬盘,直到执行close()方法后,才会将所有的写入操作反应到硬盘上。在这过程中,如果想将内存中的文件修改,立刻保存到硬盘上,可以使用f.flush()方法。
fp =
Comments NOTHING