用Python筛选国考职位表
目錄
- 1 前言
- 2 Python讀寫Excel
- 3 Python正則表達式
- 3.1 基礎知識
- 3.2 實例分析
- 4 pandas查詢
- 4.1 Series查詢
- 4.2 DataFrame查詢
- 5 國考職位表篩選
- 參考文獻
- 后記
1 前言
??2021國考在即,你報名了嗎?如果你的office耍得好,三下五除二便能篩選出符合自己的心儀職位;但若是耍得差,那可就……今天,咱們聊聊如何用Python篩選國考職位表——包括Excel文件讀取、條件查詢等。
2 Python讀寫Excel
??Python讀寫Excel的方法其實很多,比如:
- xlrd,xlwt,xlutils模塊
- openpyxl模塊
- pandas.read_excel,pandas.to_excel等函數
- ......
其中,最高效、最簡潔的方法莫過于pandas提供的各種Excel操作函數。
??(1)讀取Excel:
import pandas as pd''' pd.read_excel(io, sheetname=0,header=0,skiprows=None,index_col=None,names=None,arse_cols=None,date_parser=None,na_values=None,thousands=None, convert_float=True,has_index_names=None,converters=None,dtype=None,true_values=None,false_values=None,engine=None,squeeze=False,**kwds) ''' # sheet_name: 指定表 df1=pd.read_excel("test.xlsx") #default: Sheet1 df2=pd.read_excel("test.xlsx",sheet_name='Sheet1') #Sheet1 df3=pd.read_excel("test.xlsx",sheet_name=1) #Sheet2# header:指定作為columns的行(default=0),數據為列名行以下的數據(不含列名可設header=None) df4=pd.read_excel("test.xlsx ",sheet_name=0,header=2)# index_col: 指定作為index的列 df5=pd.read_excel("test.xlsx ",sheet_name=0,index_col=1)# names: 以list重新指定columns df6=pd.read_excel("test.xlsx ",sheet_name=0,names=["列一","列二","列三","列四","列五"])# skiprows:省略指定的行(columns的序號=0) df7=pd.read_excel("test.xlsx ",sheet_name=0,skiprows=[1,3,4])# usecols: 指定導入的columns df8=pd.read_excel("test.xlsx ",sheet_name=0,usecols=[0,3]) df9=pd.read_excel("test.xlsx ",sheet_name=0,usecols=["學歷","應屆"])??(2)寫入Excel:
import pandas as pddin=pd.DataFrame([("張三","301",370),("李四","302",500),("王五","303",600),("趙六","302",580),("郭七 ","303",700)],columns=["name","class","scores"])din.to_excel("stu_scores.xlsx",index=False) #忽略行標index保存3 Python正則表達式
??正則表達式是一個能匹配字符串的模板,它作為某些方法(如re.match、re.search、re.split、pandas.Series.str.contains)的參數。正則表達式=普通字符+特殊字符(元字符)。
3.1 基礎知識
??元字符清單見下表:
| . | 匹配除換行符外的任何字符。在DOTALL模式中也能匹配換行符 |
| \ | 轉義字符(使用后改變字符原義) |
| * | 匹配前一字符n≥0次 |
| + | 匹配前一字符n≥1次 |
| ? | 匹配前一字符n≤1次 |
| ^ | 匹配字符串開頭,在多行模式中匹配每行的開頭 |
| $ | 匹配字符串結尾,在多行模式中匹配每行的末尾 |
| | | 從左到右匹配 |左右任一 表達式。若 | 沒包含在()內,則其范圍是整個表達式 |
| (...) | 將正則表達式分組,編號從1開始。(a|b) #a or b、(c){3} #ccc |
| [...] | 字符集合,匹配此集合內任一元素。特殊字符于集合中均變成普通字符。可用-構成范圍,如[a-c]等價于[abc] |
| {,} | {m},{m,n},{m,},{,n}分別匹配前一個字符m,[m,n],[m,∞],[0,n]次 |
??正則表達式預定義字符見下表:
| \d | 匹配0~9中任一數字字符,即[0-9] |
| \D | 匹配任一非數字字符,即[^0-9] |
| \s | 匹配空白字符,即[\f\n\r\t\v](走紙換頁、換行、回車、橫向制表、豎向跳格) |
| \S | 匹配非空白字符,即[^\f\n\r\t\v] |
| \w | 匹配任一單詞字符,即[a-zA-Z0-9_] |
| \W | 匹配任一非單詞字符,即[^a-zA-Z0-9_] |
| \A | 匹配字符串開頭,即^ |
| \Z | 匹配字符串結尾,即$ |
| \b | 匹配字母數字與非字母數字的邊界(異質之邊界) |
| \B | 匹配字母數字與字母數字、非字母數字與非字母數字的邊界(同質之邊界) |
備注:①\d應寫成\\d(防轉義)或r"\d"(Python原生字符串);②Python標識符可表示為r"[a-zA-Z_][\w$]*"(以字母或下劃線打頭,后接[0,∞]個單詞字符);③\b,\B是單詞邊界,不匹配任何實際字符(是間隙),且\B是\b的非(補)。深入了解可參考博文:正則表達式里\b和\B,Python實例。
??正則表達式的特殊分組見下表:
| (?P<name>...) | 將正則表達式分組。除默認分組編號外附加一個別名name |
| \number | 引用分組編號為number的分組(默認編號) |
| (?P=name) | 引用別名為name的分組 |
備注:①r"\b(?P<my_group1>\w+)\b\s+(?P=my_group1)\b"中'\\w+'(或寫成r'\w+')編號為1,別名為my_group1,后面的(?P=my_group1)是對'\\w+'的引用。②r"\b(\w+)\b\s+\1\b"中'\\w+'編號為1,后面的\1是對'\\w+'的引用。
??一般說來,re模塊方法的參數有:①正則表達式pattern、②需匹配的字符串string、③匹配模式flags(多個flag可用|連接)。其中匹配模式見下表:
| re.A或re.ASCII | 預定義字符類\w,\W,\b,\B,\d,\D,\s,\S僅匹配ASCII字符。Python3默認匹配Unicode字符。 |
| re.I或re.IGNORECASE | 忽略大小寫 |
| re.L或re.LOCALE | 預定義字符類\w,\W,\b,\B和忽略大小寫匹配依賴于當前語言環境 |
| re.M或re.MULTILINE | 元字符^和$可匹配每一行開頭與結尾 |
| re.S或re.DOTALL | 元字符.匹配任意字符(包括換行符) |
| re.X或re.VERBOSE | 正則表達式可為多行,忽略空白字符,并可以加入注釋 |
3.2 實例分析
??(1)re.match(pattern,string,flags=0):僅在string起始位置匹配pattern,否則返回None。例如:
import restr1="To Python, or not to Python: this is a question." index=re.match('to',str1) #None??(2)re.search(pattern,string,flags=0):查詢string中首次出現pattern的位置,否則返回None。例如:
import restr1="To Python, or not to Python: this is a question." index=re.search('Python',str1) #<re.Match object; span=(3, 9), match='Python'>??(3)re.fullmatch(pattern,string,flags=0): 從string整個地匹配pattern,否則返回None。例如:
import re#str1="To Python, or not to Python: this is a question." index=re.fullmatch("Python is Fun","Python is fun") #None??(4)re.findall(pattern,string,flags=0):返回string中所有匹配pattern且不重疊的子串(列表),否則返回空列表。例如:
import restr1="To Python, or not to Python: this is a question." s=re.findall('Python',str1) #['Python', 'Python']??(5)re.finditer(pattern,string,flags=0):返回string中所有匹配pattern且不重疊的子串(迭代器),否則返回空迭代器。例如:
import restr1="To Python, or not to Python: this is a question." it=re.finditer('Python',str1) #<callable_iterator at 0x19afa872790>??(6).group([group1,...]):返回匹配group1...的一個或多個子串(re.Match object變現為具體字符串)。其中,group1可為別名或編號,0代表整個匹配表達式pattern(此時.group()=.group(0));指定多個參數.group(0,1,2,...)將返回一個匹配對應表達式的元組。例如:
import re# mathch僅在起始位置匹配;.group()變現子串; index=re.match(r'(\w+)(\w+)(\w+)',"Guido von Rossum, Programmer") #<re.Match object; span=(0, 5), match='Guido'> s=re.match(r'(\w+)(\w+)(\w+)',"Guido von Rossum, Programmer").group() #'Guido' s2=re.match('(\\w+)(\\w+)(\\w+)',"Guido von Rossum, Programmer").group(0) #'Guido'# 盡可能保證前面的pattern匹配更多 s3=re.match(r'(\w+)(\w+)(\w+)',"Guido von Rossum, Programmer").group(1) #'Gui' s4=re.match(r'(\w+)(\w+)(\w+)',"Guido von Rossum, Programmer").group(2) #'d' s5=re.match(r'(\w+)(\w+)(\w+)',"Guido von Rossum, Programmer").group(3) #'o's6=re.match(r'(\w+) (\w+) (\w+)',"Guido von Rossum, Programmer").group(0) #'Guido von Rossum' s7=re.match(r'(\w+) (\w+) (\w+)',"Guido von Rossum, Programmer").group(1) #'Guido' s8=re.match(r'(\w+) (\w+) (\w+)',"Guido von Rossum, Programmer").group(2) #'von' s9=re.match(r'(\w+) (\w+) (\w+)',"Guido von Rossum, Programmer").group(3) #'Rossum' s10=re.match(r'(\w+) (\w+) (\w+)',"Guido von Rossum, Programmer").group(1,2,3) #('Guido', 'von', 'Rossum')s11=re.match(r'(\w+) (\w+)(\w+)',"Guido von Rossum, Programmer").group(0) #'Guido von' s12=re.match(r'(\w+) (\w+)(\w+)',"Guido von Rossum, Programmer").group(1) #'Guido' s13=re.match(r'(\w+) (\w+)(\w+)',"Guido von Rossum, Programmer").group(2) #'vo' s14=re.match(r'(\w+) (\w+)(\w+)',"Guido von Rossum, Programmer").group(3) #'n'# "寫時"即能用,"引用"也可用 index=re.match(r'(?P<name>\w+ \w+ \w+),(?P<job>\w+)',"xi yuan yang,Programmer") #<re.Match object; span=(0, 23), match='xi yuan yang,Programmer'> index[0] #'xi yuan yang,Programmer' index[1] #'xi yuan yang' index[2] #'Programmer' index['name'] #'xi yuan yang' index['job'] #'Programmer'??(7).groups(default=None):返回一個包含所有匹配表達式pattern的元組。例如:
import res1=re.match(r'(\w+) (\w+) (\w+)',"xi yuan yang,Programmer").groups() # ('xi', 'yuan', 'yang') s2=re.match(r'(\w+) (\w+) (\w+)',"xi yuan yang,Programmer").group(1,2,3) # ('xi', 'yuan', 'yang')??(8).groupdict(default=None):返回一個以所有命名匹配表達式pattern為key的字典。例如:
import re# 像極了C/C++/C#/Python的格式輸出...... s=re.match(r"(?P<Stu_name>\w+),(?P<job>\w+)",'XiyuanYang,Programmer').groupdict() #{'Stu_name': 'XiyuanYang', 'job': 'Programmer'} s2=re.match(r"(?P<Stu_name>\w+), (?P<job>\w+)",'XiyuanYang,Programmer').groupdict() #None??(9).start()/.end()/.span():返回匹配子串(string匹配的pattern)于原字符串中的開始/結束/范圍。例如:
import restr1="To Python, or not to Python: this is a question." start=re.search("Python",str1).start() #3 span=re.search("Python",str1).span() #(3,9)??(10)re.split(pattern,string,maxsplit=0,flags=0)分割字符串(返回列表),maxsplit用于指定分割次數(默認整體分割)。例如:
re.split(r"\d+","0C1C++2Java3Python4Rust") #['', 'C', 'C++', 'Java', 'Python', 'Rust']# 裁剪去掉 "123及其后的異質間隙" re.split('123\\b','==123!! abc123. 123. 123abc. 123') #['==', '!! abc', '. ', '. 123abc. ', ''] # 裁剪去掉 "123及其前后的異質間隙" re.split('\\b123\\b','123 ==123!! abc123.123.123abc.123') #['', ' ==', '!! abc123.', '.123abc.', ''] # 裁剪去掉 "py=及其后的同質間隙" re.split(r'py=\B','1py=cthon py5 2py=342 py==1py2py4 pyp3 3py= pyabc') #['1py=cthon py5 2py=342 ', '=1py2py4 pyp3 3', ' pyabc'] # 裁剪去掉 "123=及其前的異質間隙與后的同質間隙" re.split('\\b123=\\B','==123!! abc123,123,123==abc,123') #['==123!! abc123,123,', '=abc,123']??(11)若某匹配表達式pattern需多次使用,可將其預編譯(re.compile(pattern,flags=0))為正則表達式對象。使用方法則同上。
import reregex=re.compile(r'(\w+) (\w+) (\w+)') s1=regex.match('xi yuan yang,Programmer').groups() #('xi', 'yuan', 'yang') s2=regex.match('mu dian yang,Teacher').groups() #('mu', 'dian', 'yang')4 pandas查詢
??pandas查詢包括Series和DataFrame查詢,又可歸結為Series查詢——因為DataFrame查詢可視為前者查詢之組合(使用邏輯運算符and,or,not或位運算符&,|,~)。
4.1 Series查詢
??(1)數值型查詢:
import pandas as pds=pd.Series([10.0,24,300.0,4,55],index=['a','b','c','d','e'])# Series使用 # ============================================================================= # s[0];s[1:3];s[[0,2,3,4]] # s['a'];s['b':'c'];s[['a','c','d','e']] # s*2;s**2 # =============================================================================# s[同維度的一個bool型Series] a=s[(s>5)&(s<150)|(~(s<300))] #type(s>5):pandas.core.series.Series c=s[s.isin([300.0,4.0])]??(2)字符串型查詢:
??①pandas.Series.str.startswith(pat,na=NaN):匹配以pat開頭的字符串(精準),空值na默認設置為NaN。此函數不支持正則表達式。
??②pandas.Series.str.endswith(pat,na=NaN):匹配以pat結尾的字符串(精準),空值na默認設置為NaN。此函數不支持正則表達式。
import numpy as np import pandas as pds=pd.Series(['41.0','24','484.0',np.nan,'cat','cgdog'],index=range(10,16)) a=s[s.str.endswith('.0',na=True)] b=s[s.str.endswith('g',na=False)]??③pandas.Series.str.contains(pat,case=True,flags=0,na=NaN,regex=True):以正則表達式(regex=True;模糊傾向)或非正則表達式(regex=False;精準傾向)進行匹配。
import numpy as np import pandas as pds=pd.Series(['41.0','24','484.0',np.nan,'Cat','cgdog'],index=range(10,16))# not regex a=s[s.str.contains('C',case=True,na=False,regex=False)] #精準匹配 b=s[s.str.contains('.0',case=False,na=True,regex=False)]# regex c=s[s.str.contains('4',case=False,na=True,regex=True)] #包含'4'的 d=s[s.str.contains('^4',case=False,na=True,regex=True)] #以'4'開頭的 e=s[s.str.contains(r'\w*\.\w*',case=False,na=False,regex=True)] #包含'.'的 import numpy as np import pandas as pds=pd.Series(['41','24(999) ','0(x)123',np.nan,' (aa)xyz','str()68'],index=range(10,16))#提取含"()"的項——兩邊非空白字符≥0,中間()有或無字符 a=s[s.str.contains(r'(\s*|\w*)\((\w+|\s*)\)(\w*|\s*)',na=False,regex=True)] b=s[s.str.contains(r'\S*\(\S*\)\S*',na=False,regex=True)] #\S*=(\s*|\w+) c=s[s.str.contains(r'(\(|\))',na=False,regex=True)]#提取"()"不靠邊的項——兩邊非空白字符≥1,中間()內有或無字符 d=s[s.str.contains(r'\S+\((\w+|\s*)\)\S+',na=False,regex=True)] e=s[s.str.contains(r'\S+\((\S*)\)\S+',na=False,regex=True)]4.2 DataFrame查詢
??DataFrame可看成Series對象構成的字典(每一列相當于一個Series),因此它的查詢即組合各個DataFrame.columns的查詢。基本寫法如下:
??(1)df[(df.列一查詢)&(df.列二查詢)|(df.列三查詢)&(~df列四查詢)],例如:
??(2)df.query('列一查詢 and 列二查詢 or 列三查詢 not 列四查詢'),例如:
import pandas as pddf=pd.DataFrame({'one':[1,2,3,4,5],'two':['a','b','c','d','e'],'three':['100.0','24.314','56','980','0.45'],'four':[45.0,78.04,4.5,6890,0.012]})param=560 result=df.query('one>=2 & two<="d" and( not three in ["56","980"]) and four<@param')5 國考職位表篩選
??點擊2021年度招考簡章下載國考職位表。解壓后,須將表首行——“招考職位由招錄機關編報,招錄專業、學歷等與職位資格條件相關的問題,由招錄機關負責解釋。” 刪除。篩選條件應按照自身情況進行修改。
import pandas as pd# <文件路徑> fileName="E:\\file home\\CivilServant\\中央機關及其直屬機構2021年度考試錄用公務員招考簡章.xls" SheetNames=["中央黨群機關","中央國家行政機關(本級)","中央國家行政機關省級以下直屬機構","中央國家行政機關參照公務員法管理事業單位"]# <篩選條件> optMajor='(測繪|測量|導航|遙感|工學類)' #專業 optEducation='(大專及以上|本科及以上|本科或碩士研究生|僅限碩士研究生|碩士研究生及以上)' #學歷 optPolity=['不限','中共黨員或共青團員'] #政治面貌 optWorkyears="無限制" #基層工作最低年限 optWorkExperience="無限制" #服務基層項目工作經歷''' 【一些特殊備注】 (1)限2020年和2021年應屆畢業生(√) (2)2021年畢業的高校畢業生(高等教育各階段均需取得相應學歷學位)(×) (3)高校應屆畢業生(高等教育各階段均需取得相應學歷學位)(×) (4)2021年應屆高校畢業生,本單位不提供宿舍,在本單位最低服務年限為5年(×) (5)限普通高等學校2021年應屆畢業生;2.各職位明確的專業類目錄按教育部《普通高等學校本科專業目錄(2020年版)》確定,報考人員最高學歷專業須為相應職位明確的專業類目錄下設專業(畢業證書、學位證書均為同一專業,含研究生專業對應的一級學科專業)(×) 【排除條件】 (1)有"2021"+有"應屆"+無"2020"→→→不要 (2)有"2021"+有"應屆"+有"2020年版"→→→不要 (3)有"2021"+無"應屆"→→→不要 (4)無"2021"+有"應屆"→→→不要 '''# <文件讀取及刷選> resultData=pd.DataFrame() print("【考試類別】 "+"【招考人數】 "+"【專業】 "+"【學歷】 "+"【政治面貌】 "+"【基層工作最低年限】 "+"【服務基層項目工作經歷】") for sheet_name in SheetNames:ExcelData=pd.read_excel(fileName,sheet_name) #文件讀取# 沒有'備注'(na)是一定要的(無限制)——一次取反:na=False;二次取反:na=TrueoptMark1=(ExcelData['備注'].str.contains('2021',na=False))&(ExcelData['備注'].str.contains('應屆',na=False))&(~(ExcelData['備注'].str.contains('2020',na=True)))optMark2=(ExcelData['備注'].str.contains(r'\S*2021\S*',na=False))&(ExcelData['備注'].str.contains(r'\S*應屆\S*',na=False))&(ExcelData['備注'].str.contains(r'\S*2020年版\S*',na=False))optMark3=(ExcelData['備注'].str.contains('2021',na=False))&(~(ExcelData['備注'].str.contains('應屆',na=True)))optMark4=(ExcelData['備注'].str.contains('應屆',na=False))&(~(ExcelData['備注'].str.contains('2021',na=True)))AppJob=ExcelData[(ExcelData['專業'].str.contains(optMajor))&(ExcelData['學歷'].str.contains(optEducation))&(ExcelData['政治面貌'].isin(optPolity))&(ExcelData['基層工作最低年限']==optWorkyears)&(ExcelData['服務基層項目工作經歷']==optWorkExperience)&((~optMark1)&(~optMark2)&(~optMark3)&(~optMark4))]if len(resultData.columns)==0:resultData=AppJobelse:resultData=resultData.append(AppJob,ignore_index=False,sort=False) #拼接#resultData=pd.concat([resultData,AppJob],axis=0,join='outer',ignore_index=False,sort=False)for n in range(AppJob.shape[0]): #展示RowItem=AppJob.iloc[n]print( RowItem["考試類別"]+" "+ str(RowItem["招考人數"])+" "+ RowItem["專業"]+" "+ RowItem["學歷"]+" "+ RowItem["政治面貌"]+" "+RowItem["基層工作最低年限"]+" "+ RowItem["服務基層項目工作經歷"])# <儲存結果> resultData.to_excel("E:\\file home\\CivilServant\\滿足條件的職位表(2021).xlsx",index=False)參考文獻
- 虞歌.Python程序設計基礎[M].北京:中國鐵道出版社,2018.
- Pandas官方文檔.
- 正則表達式里\b和\B,Python實例.
后記
滴答,滴答,滴答... 老狗睜開了今天的睡眼—— 刷牙、洗臉、長褲、防曬衣和那沾滿泥土的球鞋... 電纜線、PVC管、鐵捁、螺母、扳手、地電阻測試儀... 數了一遍又一遍,仿佛數著卡上那幾個可憐的數字 沖下樓——老板:來個4元的土豆大餅! 然后,爬上那輛泥土厚垢的汽車駛向了山路盡頭...云南的天很怪 常常在太陽中下起小雨來 射得眼睛一晃一晃,浸濕了淚水 似乎 "亞洲第一、世界第三" 才配得上這北緯26°的紫外線世界很殘酷 留下了一段狗延殘喘的距離 又能怎么樣呢 敢去填填萬人坑的基礎么?總結
以上是生活随笔為你收集整理的用Python筛选国考职位表的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: rdkit入门
- 下一篇: 【IT项目管理】第8章 习题