python学习3-文件、面向对象、爬虫等

    科技2022-07-12  128

    python学习3-文件、面向对象等

    下面的内容是根据李老师在B站上的课程总结的,主要用于自己复习回顾 这一篇是接着上一篇《python学习2-函数、列表推导式等》的 36、把文档中的所有字母字符取出组成一个字符串

    #把文档中的所有字母字符取出组成一个字符串 #最差的方式 document = input() letters = '' for c in document: if c.isalpha(): letters+=c print(letters) #较好的方法 document = input() temp = [] for c in document: if c.isalpha(): temp.append(c) letters = ''.join(temp) print(letters) #更好的方式 document = input() letters = ''.join([c for c in document if c.isalpha()]) print(letters) #最好的方式——用列表生成式,时间和空间上最优 document = input() letters = ''.join(c for c in document if c.isalpha()) print(letters)

    输出结果:

    adgasdgarg6543areg adgasdgargareg adgasdgarg6543areg adgasdgargareg adgasdgarg6543areg adgasdgargareg adgasdgarg6543areg adgasdgargareg

    37、文件的读取和写入 : 文件打开的标准格式是:open(filepath,mode=‘r’,encoding=None) filepath是文件的相对或绝对路径 mode为文件的打开方式,常用的有:'r’表示读,'w’表示写,'a’表示追加 encoding为文件编码,最常用的是utf8

    fo = open("D:\\foo.txt","w") fo.write("Python is a great language .\nYeah its great!!\n") fo.close() fo = open("D:\\foo.txt","r+") str = fo.read(10) print("Read String is:",str) fo.close() fo = open("D:\\foo.txt","r+") str = fo.readline() print("Read String is:",str) fo.close() #因为每次打开都需要调用close关闭,所以用with方式更好,不需要手动关闭 with open("D:\\foo.txt","r+") str = fo.readline() print("Read String is:",str) #os库可以管理文件 import os os.rename("test1.txt","test2.txt")#将test1.txt改为test2.txt os.remove("test2.txt")#删除test2.txt #pathlib是更好的文件管理库 # from pathlib import Path # path = Path("D:\\foo.txt") # with path.open("w",encoding = 'utf8') as f: # f.write("pathlib is better.\nYeah its great!!\n") # with path.open('r',encoding = 'utf8') as f: # str = f.readline() # print("Read String is:",str) #更简便的方式,执行API函数

    38、JSON文件是一种轻量级的数据交换格式 json.dumps():对数据进行编码,将对象转换为字符串 json.loads():对数据进行解码,从字符串中将一个对象解析出来

    import json data = { 'no':1, 'name':'Runooh', 'url':'http://www.runoob.com' } json_str = json.dumps(data) #对数据进行编码,将对象转换为字符串 print("Python 原始数据:",data) print("JSON对象:",json_str) print("原始数据的数据类型是:",type(data)) print("JSON对象的数据类型是:",type(json_str)) data2 = json.loads(json_str) print("data2['name']:",data2['name']) print("data2['url']:",data2['url'])

    输出结果:

    Python 原始数据: {'no': 1, 'name': 'Runooh', 'url': 'http://www.runoob.com'} JSON对象: {"no": 1, "name": "Runooh", "url": "http://www.runoob.com"} 原始数据的数据类型是: <class 'dict'> JSON对象的数据类型是: <class 'str'> data2['name']: Runooh data2['url']: http://www.runoob.com

    用with方式更好,不需要手动关闭

    #写入json数据 with open('data.json','w') as f: json.dump(data,f) #读取数据 with open('data.json','r') as f: data = json.load(f) #Python中的None会转换为json中的null

    39、LeetCode739题中,根据每日气温列表,重新生成一个列表,对应位置的输出是你需要等待多久温度才会升高超过该日的天数如果之后都不会升高,就在该位置用0表示,使用栈结构。 例如给定列表[73,74,75,71,69,72,76,73]对应[1,1,4,2,1,1,0,0]

    def dailyTemperaturesStack(T): length = len(T) result = [0 for i in range(length)] stack = [] for i in range(length): while len(stack)>0 and T[i]>T[stack[-1]]: t = stack.pop() result[t] = i - t stack.append(i) return result a = [73,74,75,71,69,72,76,73] print(dailyTemperaturesStack(a))

    40、面向对象: 相同类中实例化出来的对象具有相同的行为,但数据成员可能各不相同

    init()函数是构造函数 del()是析构函数

    在python中,所有类的成员函数的第一个参数必须是self

    定义一个新的类,相当于定义了一种新的数据类型

    类变量通过类名访问,实例变量通过self(本对象)访问 类变量也可以通过实例进行读取,但是不能通过实例修改

    class Int: name = 'integer' #name叫做类成员,因为他定义在所有的函数之外 def __init__(self,d): #self表示当前的实例 self.data = d #data叫做对象数据成员 def add(self,d): #成员函数第一个参数必须是self return self.data + d.data a = Int(123) b = Int(45) print(Int.name) #用类的名字调用的成员也就是类成员,类成员与具体实例无关 print(a.data) print(b.data) print(a.add(b)) print('-'*35) #类变量通过类名访问,实例变量通过self(本对象)访问 #类变量也可以通过实例进行读取,但是不能通过实例修改 print(a.__class__.name) #a.__class__表示的是a所归属的这个类的name print(b.name) b.name = "new name" print(b.name) print(Int.name)

    输出结果:

    integer 123 45 168 ----------------------------------- integer integer new name integer

    40、继承: 第一个用途:子类自动拥有父类的所有成员 第二个用途:子类可以扩展 第三个用途:重载,子类可以修改父类的成员函数

    子类自动拥有父类的所有成员

    #子类自动拥有父类的所有成员 class Datatype: name = 'data type' #name叫做类成员,因为他定义在所有的函数之外 def __init__(self,d): #self表示当前的实例 self.data = d #data叫做对象数据成员 def add(self,d): #成员函数第一个参数必须是self return self.data + d.data class Int(Datatype): pass class Str(Datatype): pass a = Int(123) b = Str('abc') print(a.data) print(b.data) print(a.add(Int(45))) print(b.add(Str('defg')))

    输出结果:

    123 abc 168 abcdefg

    子类可以扩展

    class Datatype: name = 'data type' #name叫做类成员,因为他定义在所有的函数之外 def __init__(self,d): #self表示当前的实例 self.data = d #data叫做对象数据成员 def add(self,d): #成员函数第一个参数必须是self return self.data + d.data class Str(Datatype): def length(self): return len(self.data) b = Str("abc") print(b.length()) b.lower = "asdf" #新添加了实例变量lower print(b.lower)

    输出结果是: 3 asdf

    子类可以修改父类的成员函数

    ''' assert isinstance(d,int),"parameter must is int type"是做一个类型判断,确保d一定是个整数 isinstance(参数一,参数二):参数一是个实例,参数二是个类型,判断参数一是否是参数二的实例,是则返回True,否则返回Falae assert叫做断言,后边接上一个表达式,若表达式为True,程序正常执行,若为False,则会抛出断言,程序中断执行 super表示的是父类,super().__init__()表示调用了Datatype的__init__() ''' class Datatype: name = 'data type' #name叫做类成员,因为他定义在所有的函数之外 def __init__(self,d): #self表示当前的实例 self.data = d #data叫做对象数据成员 def add(self,d): #成员函数第一个参数必须是self return self.data + d.data class Int(Datatype): name = "Integer" def __init__(self,d): assert isinstance(d,int),"parameter must is int type" #判断d是否是int类型 super().__init__(d) def add(self,d): assert isinstance(d,Int),"parameter must is int type" #判断d是否是Int类型的 return super().add(d) #a = Int('123') #,因为isinstance()参数必须是整型的,所以会抛出异常 a = Int(123) #a.add(45) #45虽然是整型,但isinstance()和add()参数必须是Int的, a.add(Int(45))

    输出为:168

    ''' 继承: 第一个用途:子类自动拥有父类的所有成员 第二个用途:子类可以扩展 第三个用途:重载,子类可以修改父类的成员函数 ''' #子类自动拥有父类的所有成员 class Datatype: name = 'data type' #name叫做类成员,因为他定义在所有的函数之外 def __init__(self,d): #self表示当前的实例 self.data = d #data叫做对象数据成员 def add(self,d): #成员函数第一个参数必须是self return self.data + d.data class Int(Datatype): pass class Str(Datatype): pass a = Int(123) b = Str('abc') print(a.data) print(b.data) print(a.add(Int(45))) print(b.add(Str('defg'))) print('-'*35) #子类可以扩展 class Datatype: name = 'data type' #name叫做类成员,因为他定义在所有的函数之外 def __init__(self,d): #self表示当前的实例 self.data = d #data叫做对象数据成员 def add(self,d): #成员函数第一个参数必须是self return self.data + d.data class Str(Datatype): def length(self): return len(self.data) b = Str("abc") print(b.length()) b.lower = True #新添加了实例变量lower print(b.lower) print('-'*35) #子类可以修改父类的成员函数 ''' assert isinstance(d,int),"parameter must is int type"是做一个类型判断,确保d一定是个整数 isinstance(参数一,参数二):参数一是个实例,参数二是个类型,判断参数一是否是参数二的实例,是则返回True,否则返回Falae assert叫做断言,后边接上一个表达式,若表达式为True,程序正常执行,若为False,则会抛出断言,程序中断执行 super表示的是父类,super().__init__()表示调用了Datatype的__init__() ''' class Datatype: name = 'data type' #name叫做类成员,因为他定义在所有的函数之外 def __init__(self,d): #self表示当前的实例 self.data = d #data叫做对象数据成员 def add(self,d): #成员函数第一个参数必须是self return self.data + d.data class Int(Datatype): name = "Integer" def __init__(self,d): assert isinstance(d,int),"parameter must is int type" #判断d是否是int类型 super().__init__(d) def add(self,d): assert isinstance(d,Int),"parameter must is int type" #判断d是否是Int类型的 return super().add(d) #a = Int('123') #,因为isinstance()参数必须是整型的,所以会抛出异常 a = Int(123) #a.add(45) #45虽然是整型,但isinstance()和add()参数必须是Int的, a.add(Int(45)) #子类具有多个类型 a = Int(123) b = Str('abc') print(isinstance(a,Int)) print(isinstance(b,Str)) print(isinstance(a,Datatype)) print(isinstance(a,Datatype))

    输出结果:

    123 abc 168 abcdefg ----------------------------------- 3 True ----------------------------------- True True True True

    41、assert isinstance(d,int),"parameter must is int type"是做一个类型判断,确保d一定是个整数 isinstance(参数一,参数二):参数一是个实例,参数二是个类型,判断参数一是否是参数二的实例,是则返回True,否则返回Falae assert叫做断言,后边接上一个表达式,若表达式为True,程序正常执行,若为False,则会抛出断言,程序中断执行 super表示的是父类,super().init()表示调用了Datatype的__init__()

    class Datatype: name = 'data type' #name叫做类成员,因为他定义在所有的函数之外 def __init__(self,d): #self表示当前的实例 self.data = d #data叫做对象数据成员 def add(self,d): #成员函数第一个参数必须是self return self.data + d.data class Int(Datatype): name = "Integer" def __init__(self,d): assert isinstance(d,int),"parameter must is int type" #判断d是否是int类型 super().__init__(d) def add(self,d): assert isinstance(d,Int),"parameter must is int type" #判断d是否是Int类型的 return super().add(d) #a = Int('123') #,因为isinstance()参数必须是整型的,所以会抛出异常 a = Int(123) #a.add(45) #45虽然是整型,但isinstance()和add()参数必须是Int的, a.add(Int(45))

    42、封装: Python可以限制外部访问数据成员和成员函数,这种阻止直接访问的机制被称为封装 对私有成员以添加下划线前缀_或两个下划线__的方式进行限制

    class JustCounter: __secretCount = 0 def count(self): self.__secretCount+=1 print(self.__secretCount) counter = JustCounter() counter.count() counter.count() #print(counter.__secrestCount)# =>'JustCounter' object has no attribute '__secrestCount' counter.__secretCount = 5 #这两句能正常运行,实际上是新定义了一个实例变量,并赋值为5 print(counter.__secretCount) #访问的并不是类成员变量,而是新定义的实例变量 counter.count() print(counter._JustCounter__secretCount) #实际上类成员变量是被自动改名了,使用全名仍然可以访问该成员变量,python中没有严格的封装

    输出结果:

    1 2 5 3 3

    43、多态: 对不同的类型数据采用相同的接口进行处理,会产生不同的结果

    class Parrot: def fly(self): print("Parrot can fly") class Penguin: def fly(self): print("Penguin can't fly") def flying_test(bird): bird.fly() blu = Parrot() peggy = Penguin() flying_test(blu) flying_test(peggy) ''' 操作符重载 ''' class Datatype: name = "Data Type" def __init__(self,d): self.data = d def add(self,d): return self.data+d.data class Int(Datatype): name = "Integer" def __init__(self,d): assert isinstance(d,int),"parameter must be int type" super().__init__(d) def __add__(self,d): assert isinstance(d,Int),"parameter must be Int type" return super().add(d) a = Int(123) b = Int(45) print(a+b)

    输出结果:

    Parrot can fly Penguin can't fly 168

    44、模块帮助用户把大的程序切分成很多小的、易管理的和易组织的文件 提供了代码的复用 用户可以把最常用的函数封装成一个模块并用import进行导入

    # %%writefile是jupyter的魔法命令,会将当前单元格中的内容保存在一个文件中 # %%writefile Example.py # def add(a,b): # return a + b # import Example # print(Example.add(1,5)) import math as m #as 指重命名 print("The value of pi is:",m.pi) #可以引入模块中的一部分 from math import pi,e print(pi) print(e) #可以使用‘*’导入模块中的所有内容,与直接import不同,不需要使用模块作为前缀 from math import * print("The value of pi is :",pi) #为了更好的组织模块,可以使用包(Package)将多个相似的模块组织一起 #一个模块相当于一个文件,一个包相当于一个文件夹 from sklearn.neighbors import KNeighborsClassifier #其中sklearn就是包,neighbors就是模块,KNeighborsClassifier就是要从模块里引入的东西

    输出结果:

    The value of pi is: 3.141592653589793 3.141592653589793 2.718281828459045 The value of pi is : 3.141592653589793

    45、爬取GDP

    #爬取GDP from selenium import webdriver from bs4 import BeautifulSoup import csv out = open('D:\\gdpallyear.csv','w',newline='') csv_write = csv.writer(out,dialect = 'excel') #转化为一个csv文件 #上边两行要在循环外,也就是只打开一次,如果放在循环内的话,每次循环都打开一次 #新的数据会覆盖掉原来的数据,导致只留下最后的数据 driver = webdriver.Chrome() #这个只适用于chrome浏览器 for year in range(1960,2020): url = "https://www.kylc.com/stats/global/yearly/g_gdp/%d.html"%year xpath = "/html/body/div[2]/div[1]/div[5]/div[1]/div/div/div/table" #xpath是该元素在网页中的绝对位置 driver.get(url) table1 = driver.find_element_by_xpath(xpath).get_attribute('innerHTML') #通过find_element_by_xpath()找到该元素,该元素是一个控件,通过get_attribute('innerHTML')得到该控件的源代码 soup = BeautifulSoup(table1,"html.parser") #对table控件进行解析 table = soup.find_all('tr') for row in table: cols = [col.text for col in row.find_all('td')] #text取标签中的内容 if len(cols)==0 or not cols[0].isdigit(): #删除不需要的数据 continue cols.append(year) csv_write.writerow(cols) #把新得到的数据不断写入文件中 print(cols) out.close() #合理关闭新打开的文件 driver.close() #自动关闭打开的网页

    46、批量下载表情包

    #requests要求获取的必须是静态网页,也就是已经静态生成的 import requests from bs4 import BeautifulSoup from pathlib import Path #下载即保存为本地文件,处理本地文件时建议用pathlib import time for i in range(1,4): url = f'https://fabiaoqing.com/biaoqing/lists/page/{i}.html' response = requests.get(url) time.sleep(3) #初始化BeautifulSoup对象,选择lxml HTML解析器 soup = BeautifulSoup(response.content,'lxml') #response.text和response.context都是获取最终结果,但response.text是以文本的形式回馈的,response.context是以二进制的形式回馈的 img_list = soup.find_all('img',class_ = 'ui image lazy') #class要加_,这样才表示属性 for index,img in enumerate(img_list):#通过enumerate列举获得的信息,列举的主要目的是获取一个index image = img.get('data-original') #获得图片的下载网址 content = requests.get(image).content #调用requests.get()得到相应网址的内容,因为图片都是以二进制的形式存储的,因此只能调用.content而不能调用.text file = Path('D:\pachong\Emotion') / f'{index} {Path(image).suffix}' #f'{index} {Path(image).suffix}' 给获得的表情包命名,suffix是获取后缀 file.write_bytes(content) #write_bytes是书写二进制

    47、网页的动作模拟:讲解网页元素赋值,模拟鼠标点击等操作,实现查询、跳转等功能

    from selenium import webdriver from selenium.webdriver.common.action_chains import ActionChains #做动作模拟的库 from bs4 import BeautifulSoup #网页解析 import time driver = webdriver.Chrome() #初始化driver url = 'https://kyfw.12306.cn/otn/leftTicket/init' #访问网址 driver.get(url) #给driver传入访问网址 fromStation = '青岛' #出发地 toStation = '葫芦岛' #目的地 month = 1 #0表示本月,1表示下一个月 day = 1 #出发的日期,这里是次月的1号 #设定相关控件的xpath #相对xpath://控件类型[@属性=特定值] 控件类型处为‘*’,则表示任意控件类型 xFrom = '//*[@id="fromStationText"]' #出发地 xTo = '//*[@id="toStationText"]' #目的地 xDate = '//*[@id="train_date"]' #日期输入框 //*[@id="train_date"] xMonth = '//div[@class="cal-cm"]' #日历菜单 /html/body/div[37]/div[1]/div[2] xQuery = '//*[@id="query_ticket"]' #查询按钮 xTable = '//*[@id="t-list"]/table' #数据表格 def inputstation(xPath,station): #模拟输入车站 city = driver.find_element_by_xpath(xPath) #定位出发地 ActionChains(driver).click(city).send_keys(station).perform() #输入出发地 station = city.find_element_by_xpath('//span[text()="'+station+'"]') #定位出发地菜单 station.click() #点击确定 def inputdate(xMonth,xDate,startmonth,startdate): driver.find_element_by_xpath(xDate).click() #点击出发日期输入栏 Month = driver.find_elements_by_xpath(xMonth)[month] #输入出发日期 Day = Month.find_element_by_xpath('//div[text()=%d]'%day) Day.click() def result(): print(','.join(['车次','出发站','到达站','出发时间','到达时间','历时', '商务座/特等座','一等座','二等座/二等包座','高级/软卧', '软卧/一等卧','动卧','硬卧/二等卧','软座','硬座','无座', '其他','备注'])) rows = driver.find_elements_by_xpath('//tr[starts-with(@id,"ticket")]') for row in rows: soup = BeautifulSoup(row.get_attribute('innerHTML'),"html.parser") tds = soup.find_all('td') train = [element.text for element in tds[0].find_all(['a','strong'])] train.extend([td.text for td in tds[1:]]) print(','.join(train)) inputstation(xFrom,fromStation) inputstation(xTo,toStation) inputdate(xMonth,xDate,month,day) driver.find_element_by_xpath(xQuery).click() time.sleep(3) result() #输出结果 driver.close()

    输出结果:

    车次,出发站,到达站,出发时间,到达时间,历时,商务座/特等座,一等座,二等座/二等包座,高级/软卧,软卧/一等卧,动卧,硬卧/二等卧,软座,硬座,无座,其他,备注 K956,青岛北,葫芦岛,18:07,09:40,15:33,--,--,--,--,6,--,,--,,,--,预订 K702,青岛北,葫芦岛,18:30,10:26,15:56,--,--,--,--,7,--,1,--,,,--,预订 K1054,青岛北,葫芦岛,18:39,10:42,16:03,--,--,--,--,5,--,,--,,,--,预订
    Processed: 0.015, SQL: 8