




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)
文檔簡介
PythonCrawlerDevelopment極客學(xué)院J互聯(lián)網(wǎng)+職業(yè)技能系列
Python爬蟲開發(fā)從入門到實戰(zhàn)(微課版)人民郵電出版社謝乾坤
著
PythonCrawlerDevelopmen1第3章正則表達(dá)式與文件操作
在爬蟲的開發(fā)中,需要把有用的信息從一大段文本中提取出來。正則表達(dá)式是提取信息的方法之一。
正則表達(dá)式雖然不是最簡單的也不是最高效的數(shù)據(jù)提取方法,但它是最直接的。而且在某些情況下,只有使用正則表達(dá)式才能達(dá)到目的。學(xué)好正則表達(dá)式,是開發(fā)爬蟲的第一步。第3章正則表達(dá)式與文件操作在爬蟲的開發(fā)2
通過這一章的學(xué)習(xí),你將會掌握如下知識。(1)正則表達(dá)式的基本符號。(2)如何在Python中使用正則表達(dá)式。(3)正則表達(dá)式的提取技巧。(4)Python讀寫文本文件和CSV文件。通過這一章的學(xué)習(xí),你將會掌握如下知識33.1正則表達(dá)式
正則表達(dá)式(RegularExpression)是一段字符串,它可以表示一段有規(guī)律的信息。Python自帶一個正則表達(dá)式模塊,通過這個模塊可以查找、提取、替換一段有規(guī)律的信息。
在程序開發(fā)中,要讓計算機(jī)程序從一大段文本中找到需要的內(nèi)容,就可以使用正則表達(dá)式來實現(xiàn)。
使用正則表達(dá)式有如下步驟。(1)尋找規(guī)律。(2)使用正則符號表示規(guī)律。(3)提取信息。3.1正則表達(dá)式正則表達(dá)式(Regul41.點號“.”
一個點號可以代替除了換行符以外的任何一個字符,包括但不限于英文字母、數(shù)字、漢字、英文標(biāo)點符號和中文標(biāo)點符號。2.星號“*”
一個星號可以表示它前面的一個子表達(dá)式(普通字符、另一個或幾個正則表達(dá)式符號)0次到無限次。3.1.1正則表達(dá)式的基本符號1.點號“.”3.1.1正則表達(dá)式的基本符號53.問號“?”
問號表示它前面的子表達(dá)式0次或者1次。注意,這里的問號是英文問號。
4.反斜杠“\”
反斜杠在正則表達(dá)式里面不能單獨使用,甚至在整個Python里都不能單獨使用。反斜杠需要和其他的字符配合使用來把特殊符號變成普通符號,把普通符號變成特殊符號。3.問號“?”6
反斜杠不僅可以把特殊符號變成普通符號,還可以把普通符號變成特殊符號。
例如“n”只是一個普通的字母,但是“\n”代表換行符。
在Python開發(fā)中,經(jīng)常遇到的轉(zhuǎn)義字符,如表3-1所示。反斜杠不僅可以把特殊符號變成普通符號,還可7轉(zhuǎn)義字符意義\n換行符\t制表符\\普通的反斜杠\'單引號\"雙引號\d數(shù)字
表3-1常見的轉(zhuǎn)義字符轉(zhuǎn)義字符意義\n換行符\t制表符\\普通的反斜杠\'單引號\85.?dāng)?shù)字“\d”
正則表達(dá)式里面使用“\d”來表示一位數(shù)字。為什么要用字母d呢?因為d是英文“digital(數(shù)字)”的首字母。
再次強(qiáng)調(diào)一下,“\d”雖然是由反斜杠和字母d構(gòu)成的,但是要把“\d”看成一個正則表達(dá)式符號整體。
6.小括號“()”
小括號可以把括號里面的內(nèi)容提取出來。5.?dāng)?shù)字“\d”93.1.2在Python中使用正則表達(dá)式Python已經(jīng)自帶了一個功能非常強(qiáng)大的正則表達(dá)式模塊。使用這個模塊可以非常方便地通過正則表達(dá)式來從一大段文字中提取有規(guī)律的信息。Python的正則表達(dá)式模塊名字為“re”,也就是“regularexpression”的首字母縮寫。在Python中需要首先導(dǎo)入這個模塊再進(jìn)行使用。導(dǎo)入的語句為:importre3.1.2在Python中使用正則表達(dá)式Pyt101.findallPython的正則表達(dá)式模塊包含一個findall方法,它能夠以列表的形式返回所有滿足要求的字符串。
findall的函數(shù)原型為:re.findall(pattern,string,flags=0)pattern表示正則表達(dá)式,string表示原來的字符串,flags表示一些特殊功能的標(biāo)志。
1.findall11findall的結(jié)果是一個列表,包含了所有的匹配到的結(jié)果。如果沒有匹配到結(jié)果,就會返回空列表,如圖3-1所示。圖3-1findall返回的內(nèi)容findall的結(jié)果是一個列表,包含了所有12
當(dāng)需要提取某些內(nèi)容的時候,使用小括號將這些內(nèi)容括起來,這樣才不會得到不相干的信息。如果包含多個“(.*?)”怎么返回呢?如圖3-2所示,返回的仍然是一個列表,但是列表里面的元素變?yōu)榱嗽M,元組里面的第1個元素是賬號,第2個元素為密碼。圖3-2多個括號內(nèi)的內(nèi)容會以元組形式返回當(dāng)需要提取某些內(nèi)容的時候,使用小括號將這些13
請注意代碼中的冒號和逗號,圖3-1代碼中為中文冒號和中文逗號;圖3-2代碼中為英文冒號和英文逗號。在實際使用正則表達(dá)式的過程中,中英文標(biāo)點符號混淆常常會導(dǎo)致各種問題。特別是冒號、逗號和引號,雖然中英文看起來非常相似,但實際上中文冒號和英文冒號是不一樣的,中文逗號和英文逗號也是不一樣的。
在某些字體里面,這種差異甚至無法察覺,因此在涉及正則表達(dá)式中的標(biāo)點符號時,最好直接復(fù)制粘貼,而不要手動輸入。請注意代碼中的冒號和逗號,圖3-1代碼中為中14
函數(shù)原型中有一個flags參數(shù)。這個參數(shù)是可以省略的。當(dāng)不省略的時候,具有一些輔助功能,例如忽略大小寫、忽略換行符等。這里以忽略換行符為例來進(jìn)行說明,如圖3-3所示。圖3-3使用re.S作為flag來忽略換行符函數(shù)原型中有一個flags參數(shù)。這個參數(shù)是15
在爬蟲的開發(fā)過程中非常容易出現(xiàn)這樣的情況,要匹配的內(nèi)容存在換行符“\n”。要忽略換行符,就需要使用到“re.S”這個flag。雖然說匹配到的結(jié)果中出現(xiàn)了“\n”這個符號,不過總比什么都得不到強(qiáng)。內(nèi)容里面的換行符在后期清洗數(shù)據(jù)的時候把它替換掉即可。在爬蟲的開發(fā)過程中非常容易出現(xiàn)這樣的情況,162.searchsearch()的用法和findall()的用法一樣,但是search()只會返回第1個滿足要求的字符串。一旦找到符合要求的內(nèi)容,它就會停止查找。對于從超級大的文本里面只找第1個數(shù)據(jù)特別有用,可以大大提高程序的運(yùn)行效率。
search()的函數(shù)原型為:re.search(pattern,string,flags=0)2.search17
對于結(jié)果,如果匹配成功,則是一個正則表達(dá)式的對象;如果沒有匹配到任何數(shù)據(jù),就是None。
如果需要得到匹配到的結(jié)果,則需要通過.group()這個方法來獲取里面的值,如圖3-4所示。圖3-4使用.group()來獲取search()方法找到的結(jié)果對于結(jié)果,如果匹配成功,則是一個正則表達(dá)式18
只有在.group()里面的參數(shù)為1的時候,才會把正則表達(dá)式里面的括號中的結(jié)果打印出來。.group()的參數(shù)最大不能超過正則表達(dá)式里面括號的個數(shù)。參數(shù)為1表示讀取第1個括號中的內(nèi)容,參數(shù)為2表示讀取第2個括號中的內(nèi)容,以此類推,如圖3-5所示。
只有在.group()里面的參數(shù)為1的時候,19圖3-5.group()的參數(shù)意義圖3-5.group()的參數(shù)意義203.“.*”和“.*?”的區(qū)別
在爬蟲開發(fā)中,.*?這3個符號大多數(shù)情況下一起使用。
點號表示任意非換行符的字符,星號表示匹配它前面的字符0次或者任意多次。所以“.*”表示匹配一串任意長度的字符串任意次。這個時候必須在“.*”的前后加其他的符號來限定范圍,否則得到的結(jié)果就是原來的整個字符串。
如果在“.*”的后面加一個問號,變成“.*?”,那么可以得到什么樣的結(jié)果呢?問號表示匹配它前面的符號0次或者1次。于是.*?的意思就是匹配一個能滿足要求的最短字符串。
3.“.*”和“.*?”的區(qū)別21
這樣說起來還是非常抽象,下面通過一個實際的例子來進(jìn)行說明。請看下面這一段話:我的微博密碼是:1234567,QQ密碼是:33445566,銀行卡密碼是:888888,Github密碼是:999abc999,幫我記住它們
這段話有一個顯著的規(guī)律,即密碼是:xxxxxx,”,也就是在“密碼是”這3個漢字的后面跟一個中文的冒號,冒號后面是密碼,密碼后面是中文的逗號。
這樣說起來還是非常抽象,下面通過一個實際的例22
如果想把這4個密碼提取出來,可以構(gòu)造以下兩個正則表達(dá)式:密碼是:(.*),密碼是:(.*?),
配合Python的findall方法,得到結(jié)果如圖3-6圖所示。
如果想把這4個密碼提取出來,可以構(gòu)造以下23圖3-6使用“.*”和“.*?”返回的結(jié)果圖3-6使用“.*”和“.*?”返回的結(jié)果24
使用“(.*)”得到的是只有一個元素的列表,里面是一個很長的字符串。
使用第2個正則表達(dá)式“(.*?)”,得到的結(jié)果是包含4個元素的列表,每個元素直接對應(yīng)原來文本中的每個密碼。
一句話總結(jié)如下。①“.*”:貪婪模式,獲取最長的滿足條件的字符串。②“.*?”:非貪婪模式,獲取最短的能滿足條件的字符串。使用“(.*)”得到的是只有一個元素的列表253.1.3正則表達(dá)式提取技巧
1.不需要compile網(wǎng)上很多人的文章中,正則表達(dá)式使用pile()這個方法,導(dǎo)致代碼變成下面這樣:importreexample_text='我是kingname,我的微博賬號是:kingname,密碼是:12345678,QQ賬號是:99999,密碼是:890abcd,銀行卡賬號是:000001,密碼是:654321,Github賬號是:99999@,密碼是:7777love8888,請記住他們。'new_pattern=pile('賬號是:(.*?),密碼是:(.*?),',re.S)user_pass=re.findall(new_pattern,example_text)print(user_pass)3.1.3正則表達(dá)式提取技巧
1.不需要compile26這種寫法雖然結(jié)果正確,但純粹是畫蛇添足,是對Python的正則表達(dá)式模塊沒有理解透徹的體現(xiàn),是從其他啰嗦的編程語言中帶來的壞習(xí)慣。如果閱讀Python的正則表達(dá)式模塊的源代碼,就可以看出pile()是完全沒有必要的。對比pile()和re.findall()在源代碼中的寫法,如圖3-7所示的兩個方框。這種寫法雖然結(jié)果正確,但純粹是畫蛇添足,是對Pyt27圖3-7Python正則表達(dá)式模塊中的re.findall()和pile()圖3-7Python正則表達(dá)式模塊中的re.findal28
使用pile()的時候,程序內(nèi)部調(diào)用的是_compile()方法;當(dāng)使用re.finall()的時候,在模塊內(nèi)部自動先調(diào)用了_compile()方法,再調(diào)用findall()方法。re.findall()自帶pile()的功能,所以沒有必要使用pile()。Python3中正則表達(dá)式模塊的源代碼的入口文件為re.py。這個文件里面的注釋就是學(xué)習(xí)Python正則表達(dá)式模塊非常好的文檔,它包含了正則表達(dá)式各種符號的簡單說明和這個模塊內(nèi)部各個方法的使用,如圖3-8所示。
使用pile()的時候,程序內(nèi)部29圖3-8Pythonre.py文件自帶的文檔圖3-8Pythonre.py文件自帶的文檔302.先抓大再抓小
一些無效內(nèi)容和有效內(nèi)容可能具有相同的規(guī)則。這種情況下很容易把有效內(nèi)容和無效內(nèi)容混在一起,如下面這段文字:
有效用戶:姓名:張三姓名:李四姓名:王五2.先抓大再抓小31無效用戶:姓名:不知名的小蝦米姓名:隱身的張大俠
有效用戶和無效用戶的名字前面都以“姓名:”開頭,如果使用“姓名:(.*?)\n”來進(jìn)行匹配,就會把有效信息和無效信息混在一起,難以區(qū)分,如圖3-9所示。無效用戶:32圖3-9使用“姓名:(.*?)\n”導(dǎo)致有效內(nèi)容和無效內(nèi)容混在一起圖3-9使用“姓名:(.*?)\n”導(dǎo)致有效內(nèi)容和無效33
要解決這個問題,就需要使用先抓大再抓小的技巧。先把有效用戶這個整體匹配出來,再從有效用戶里面匹配出人名,代碼和運(yùn)行效果如圖3-10所示。先抓大再抓小的思想會貫穿整個爬蟲開發(fā)過程,一定要重點掌握。圖3-10代碼和運(yùn)行效果要解決這個問題,就需要使用先抓大再抓小的技巧343.括號內(nèi)和括號外
在上面的例子中,括號和“.*?”都是一起使用的,因此可能會有讀者認(rèn)為括號內(nèi)只能有這3種字符,不能有其他普通的字符。但實際上,括號內(nèi)也可以有其他字符,對匹配結(jié)果的影響如圖3-11所示。圖3-11括號里有無其他字符對匹配結(jié)果的影響3.括號內(nèi)和括號外圖3-11括號里有無其他字符對匹配結(jié)果353.2Python文件操作Python的文件操作涉及對文件的讀/寫與編碼的處理,是學(xué)習(xí)爬蟲的必備知識。3.2.1使用Python讀/寫文本文件使用Python來讀/寫文本需要用到“open”這個關(guān)鍵字。它的作用是打開一個文件,并創(chuàng)建一個文件對象。使用Python打開文件,有兩種寫法。第1種方式如下:f=open('文件路徑','文件操作方式',encoding='utf-8')對文件進(jìn)行操作f.close()3.2Python文件操作Python的文件操36第2種方式,使用Python的上下文管理器:withopen('文件路徑','文件操作方式',encoding='utf-8')asf:
對文件進(jìn)行操作第1種方式需要手動關(guān)閉文件,但是在程序開發(fā)中經(jīng)常會出現(xiàn)忘記關(guān)閉文件的情況。第2種方法不需要手動關(guān)閉文件,只要代碼退出了縮進(jìn),Python就會自動關(guān)閉文件。第2種方式,使用Python的上下文管理器:371.使用Python讀文本文件
使用Python打開一個文本文件時,首先要保證這個文件是存在的。在讀文件的時候,“文件操作方式”這個參數(shù)可以省略,也可以寫成“r”,也就是read的首字母。
文件路徑可以是絕對路徑,也可以是相對路徑。如果是絕對路徑,Linux和MacOS不能直接使用“~”表示“home目錄”,因為Python不認(rèn)識“~”這個符號。如果非要使用這個符號,需要使用Python的“os”模塊,代碼如下:importosreal_path=os.path.expanduser('~/project/xxx')1.使用Python讀文本文件38
這樣,Python就會將這種風(fēng)格的路徑轉(zhuǎn)化為Python能認(rèn)識的絕對路徑。
相對路徑是文本文件相對于現(xiàn)在的工作區(qū)而言的路徑,并不總是相對于當(dāng)前正在運(yùn)行的這個Python文件的路徑。在本章中,請讀者直接將文本文件和Python文件放在一起,這樣就可以直接使用文件名來打開文本文件。
文本文件的內(nèi)容和它相對于.py文件的位置如圖3-12所示。這樣,Python就會將這種風(fēng)格的路徑轉(zhuǎn)化為39圖3-12文本文件的內(nèi)容和它相對于.py文件的位置圖3-12文本文件的內(nèi)容和它相對于.py文件的位置40
使用下面的代碼來打開text.txt文件:withopen('text.txt',encoding='utf-8')asf:通過f來讀文件
這里有一個參數(shù)“encoding”。這個參數(shù)特別有用,它可以在打開文件的時候?qū)⑽募D(zhuǎn)換為UTF-8編碼格式,從而避免亂碼的出現(xiàn)。這個參數(shù)只有Python3有,在Python2中使用這個參數(shù)會報錯。如果文件是在Windows中創(chuàng)建的,并且使用UTF-8打開文件出現(xiàn)了亂碼,可以把編碼格式改為GBK。使用下面的代碼來打開text.txt文件:41
文本文件可以按行讀取,也可以直接讀取里面的所有內(nèi)容。
讀取所有行,并以列表的形式返回結(jié)果,代碼如下:
f.readlines()
運(yùn)行效果如圖3-13所示。
圖3-13使用readlines()讀取文本所有行并以列表形式返回結(jié)果文本文件可以按行讀取,也可以直接讀取里面的42
直接把文件里面的全部內(nèi)容用一個字符串返回,代碼如下:f.read()
運(yùn)行結(jié)果如圖3-14所示。圖3-14直接把整個文本內(nèi)容以一個字符串方式返回的結(jié)果直接把文件里面的全部內(nèi)容用一個字符串返回,代432.使用Python寫文本文件
使用Python寫文件也需要先打開文件,使用如下代碼來打開文件:withopen('new.txt','w',encoding='utf-8')asf:通過f來寫文件
這里多出來一個參數(shù)“w”,w是英文write的首字母,意思是以寫的方式打開文件。這個參數(shù)除了為“w”外,還可以為“a”。它們的區(qū)別在于,如果原來已經(jīng)有一個new.txt文件了,使用“w”會覆蓋原來的文件,導(dǎo)致原來的內(nèi)容丟失;而使用“a”,則會把新的內(nèi)容寫到原來的文件末尾。2.使用Python寫文本文件44
寫文件時可以直接寫一大段文本,也可以寫一個列表。
直接將一大段字符串寫入到文本中,可以使用下面這一行代碼:f.write("一大段文字")
把列表里面的所有字符串寫入到文本中,可以使用下面這一行代碼:f.writelines(['第一段話','第二段話','第三段話'])寫文件時可以直接寫一大段文本,也可以寫一45
需要特別注意,寫列表的時候,Python寫到文本中的文字是不會自動換行的,需要人工輸入換行符才可以。代碼和運(yùn)行生成的文本new.txt如圖3-15和圖3-16所示。請注意代碼第8行列表中的兩個字符串,在new.txt的第3行中被拼在了一起。圖3-15寫字符串和包含字符串的列表到文本中的代碼需要特別注意,寫列表的時候,Python寫46圖3-16寫文本生成的文件內(nèi)容結(jié)果圖3-16寫文本生成的文件內(nèi)容結(jié)果473.2.2使用Python讀/寫CSV文件CSV文件可以用Excel或者Numbers打開,得到可讀性很高的表格,如圖3-17所示。圖3-17使用Numbers打開CSV文件3.2.2使用Python讀/寫CSV文件C48CSV文件本質(zhì)上就是文本文件,但是如果直接用文本編輯器打開,可讀性并不高,如圖3-18所示。圖3-18直接用文本編輯器打開CSV文件CSV文件本質(zhì)上就是文本文件,但是如果直接49Python自帶操作CSV的模塊。使用這個模塊,可以將CSV文件的內(nèi)容轉(zhuǎn)換為Python的字典,從而方便使用。1.Python讀CSV文件
要讀取CSV文件,首先需要導(dǎo)入Python的CSV模塊:importcsvPython自帶操作CSV的模塊。使用這個50
由于CSV文件本質(zhì)上是一個文本文件,所以需要先以文本文件的方式打開,再將文件對象傳遞給CSV模塊:withopen('result.csv',encoding='utf-8')asf:reader=csv.DictReader(f)forrowinreader:
print(row)
運(yùn)行結(jié)果圖3-19所示。由于CSV文件本質(zhì)上是一個文本文件,所以需51圖3-19使用CSV模塊打開CSV文件圖3-19使用CSV模塊打開CSV文件52
代碼中,for循環(huán)得到的row是OrderedDict(有序字典),可以直接像普通字典那樣使用:username=row['username']content=row['content']reply_time=row['reply_time']
運(yùn)行結(jié)果如圖3-20所示。
代碼中,for循環(huán)得到的row是Order53圖3-20像讀字典一樣讀CSV文件圖3-20像讀字典一樣讀CSV文件54
短短幾行代碼,已經(jīng)將CSV文件轉(zhuǎn)換為字典了。
特別注意:
讀取文本內(nèi)容的代碼必須放在縮進(jìn)內(nèi)部進(jìn)行,否則會導(dǎo)致報錯,如圖3-21所示。圖3-21讀取文本內(nèi)容的代碼必須放在縮進(jìn)的里面短短幾行代碼,已經(jīng)將CSV文件轉(zhuǎn)換為字典了55
這是因為f變量里面的值是一個生成器,生成器只有在被使用(更準(zhǔn)確的說法是被迭代)的時候才會去讀文本內(nèi)容。但是退出with的縮進(jìn)以后,文件就被Python關(guān)閉了,這個時候當(dāng)然什么都讀不了。
那有沒有什么辦法可以繞過這個限制呢?當(dāng)然是有的,那就是使用列表推導(dǎo)式。圖3-22所示為使用列表推導(dǎo)式讀取文本內(nèi)容。請對比圖3-21和圖3-22第4行的不同。這是因為f變量里面的值是一個生成器,生成器只56圖3-22使用列表推導(dǎo)式讀取文本內(nèi)容圖3-22使用列表推導(dǎo)式讀取文本內(nèi)容572.Python寫CSV文件Python可以把一個字典寫成CSV文件,或者把一個包含字典的列表寫成CSV文件。Python寫CSV文件比讀CSV文件稍微復(fù)雜一點,因為要指定列名。列名要和字典的Key一一對應(yīng)。
Python寫CSV文件時需要用到csv.DictWriter()這個類。它接收兩個參數(shù):第1個參數(shù)是文件對象f;第2個參數(shù)名為fieldnames,值為字典的Key列表。
寫入CSV文件的列名行:
writer.writeheader()2.Python寫CSV文件58
將包含字典的列表全部寫入到CSV文件中:writer.writerows(包含字典的列表)
寫入一個包含字典的列表,每一個字典對應(yīng)CSV的一行。這些字典的Key必須和fieldnames相同。字典可以是普通的無序字典,所以不需要關(guān)心字典里面Key的順序,但是不能存在fieldnames里面沒有的Key,也不能缺少fieldnames里面已有的Key。
將包含字典的列表全部寫入到CSV文件中:59
寫入單個字典:writer.writerow(字典)
代碼如圖3-23所示,運(yùn)行結(jié)果如圖3-24所示。MacOS的Numbers顯示CSV文件的結(jié)果和Excel中顯示的結(jié)果可能存在差異,但是表格里面的數(shù)據(jù)應(yīng)該是一致的。
寫入單個字典:60圖3-23將包含列表的字典寫入到CSV文件中圖3-23將包含列表的字典寫入到CSV文件中61圖3-24生成的CSV文件用Numbers打開以后的結(jié)果圖3-24生成的CSV文件用Numbers打開以后的結(jié)果623.3階段案例——半自動爬蟲開發(fā)
所謂半自動爬蟲,顧名思義就是一半手動一半自動地進(jìn)行爬蟲,手動的部分是把網(wǎng)頁的源代碼復(fù)制下來,自動的部分是通過正則表達(dá)式把其中的有效信息提取出來。3.3階段案例——半自動爬蟲開發(fā)所謂半633.3.1需求分析在百度貼吧中任意尋找一個貼吧并打開一個熱門帖子,將帖子的源代碼復(fù)制下來,并保存為source.txt。Python讀入這個source.txt文件,通過正則表達(dá)式獲取用戶名、發(fā)帖內(nèi)容和發(fā)帖時間,并保存為result.csv。涉及的知識點如下。(1)在瀏覽器中查看網(wǎng)站的源代碼。(2)使用Python讀文本文件。(3)正則表達(dá)式的應(yīng)用。(4)先抓大再抓小的匹配技巧。(5)使用Python寫CSV文件。3.3.1需求分析在百度貼吧中任意尋找一個貼643.3.2核心代碼構(gòu)建1.在瀏覽器中獲取網(wǎng)頁的源代碼以Chrome瀏覽器為例來說明如何查看網(wǎng)頁的源代碼。在網(wǎng)頁上單擊鼠標(biāo)右鍵,選擇“顯示網(wǎng)頁源代碼”命令,如圖3-25所示。圖3-25選擇“顯示網(wǎng)頁源代碼”命令3.3.2核心代碼構(gòu)建1.在瀏覽器中獲取網(wǎng)頁的源代碼圖365
網(wǎng)頁源代碼如圖3-26所示。這里可以復(fù)制全部的源代碼,并粘貼到記事本中。圖3-26網(wǎng)頁源代碼網(wǎng)頁源代碼如圖3-26所示。這里可以復(fù)制全662.獲取關(guān)鍵信息
要獲取網(wǎng)站的關(guān)鍵信息,就需要觀察網(wǎng)頁源代碼的規(guī)律。
通過對比每一層樓的帖子,可以發(fā)現(xiàn)規(guī)律,即每一層樓都是從“username”開頭的,如圖3-27所示。圖3-27用戶名的規(guī)律2.獲取關(guān)鍵信息圖3-27用戶名的規(guī)律67
先來看用戶名,從圖3-27可以看出,用戶名符合這樣的規(guī)律:username="(.*?)"
再來看發(fā)帖內(nèi)容,從圖3-28可以看出,發(fā)帖內(nèi)容符合如下規(guī)律:d_post_contentj_d_post_content">(.*?)<圖3-28發(fā)帖內(nèi)容的規(guī)律先來看用戶名,從圖3-27可以看出,用戶名68
最后來看發(fā)帖時間。請注意,從圖3-29中可以看出,發(fā)帖時間需要應(yīng)用3.1.3小節(jié)所提到的“括號內(nèi)和括號外”技巧。由于方框框住的兩段內(nèi)容有著相同的開頭字符串,如何把“2017-03-1819:39”提取出來,但不要把“15樓”提取出來?這種情況下,對于正則表達(dá)式,應(yīng)該在括號里面包含一些其他的要素,才能只把時間提取出來。最后來看發(fā)帖時間。請注意,從圖3-29中可以看出69圖3-29發(fā)帖時間的規(guī)律圖3-29發(fā)帖時間的規(guī)律70
由于發(fā)帖時間總是以年開頭的,因此可以在括號里面包含“2017”,這樣就可以得到正確的年份信息。匹配年份的正則表達(dá)式如下:tail-info">(2017.*?)<由于發(fā)帖時間總是以年開頭的,因此可以在括號713.3.3調(diào)試與運(yùn)行完整的半自動爬蟲代碼如圖3-30所示,生成的CSV文件如圖3-31所示。圖3-30完整的半自動爬蟲代碼3.3.3調(diào)試與運(yùn)行完整的半自動爬蟲代碼如圖72圖3-31爬蟲生成的CSV文件圖3-31爬蟲生成的CSV文件73圖3-32把帖子的每一層樓看作一個塊圖3-32把帖子的每一層樓看作一個塊74
開始和結(jié)束標(biāo)志如圖3-33所示。
對原來的代碼進(jìn)行修改,可以得到邏輯更加合理的新代碼,如圖3-34所示。圖3-33一層樓的開始和結(jié)束標(biāo)志開始和結(jié)束標(biāo)志如圖3-33所示。圖3-3375圖3-34更合乎邏輯的半自動爬蟲代碼圖3-34更合乎邏輯的半自動爬蟲代碼763.4本章小結(jié)
本章主要講到了正則表達(dá)式和Python的文件操作。
正則表達(dá)式用來在一大段文字中提取需要的內(nèi)容,用得最多的組合是“(.*?)”。這個組合可以解決絕大多數(shù)的目標(biāo)提取問題。
使用Python讀/寫文本文件和CSV文件都需要先把文件打開,在Python中使用open這個關(guān)鍵字來打開文件。在Python中,使用CSV這個內(nèi)置的模塊可以非常方便地把CSV文件轉(zhuǎn)換成Python的字典,或者把Python的字典轉(zhuǎn)換為CSV文件。
3.4本章小結(jié)本章主要講到了正則表達(dá)式773.5動手實踐
在百度貼吧中尋找一個自己喜歡的貼吧,將其中一篇熱門帖子的每層樓的發(fā)帖人、發(fā)帖內(nèi)容和發(fā)帖時間抓取下來。3.5動手實踐在百度貼吧中尋找一個自己喜78
PythonCrawlerDevelopment極客學(xué)院J互聯(lián)網(wǎng)+職業(yè)技能系列
Python爬蟲開發(fā)從入門到實戰(zhàn)(微課版)人民郵電出版社謝乾坤
著
PythonCrawlerDevelopmen79第3章正則表達(dá)式與文件操作
在爬蟲的開發(fā)中,需要把有用的信息從一大段文本中提取出來。正則表達(dá)式是提取信息的方法之一。
正則表達(dá)式雖然不是最簡單的也不是最高效的數(shù)據(jù)提取方法,但它是最直接的。而且在某些情況下,只有使用正則表達(dá)式才能達(dá)到目的。學(xué)好正則表達(dá)式,是開發(fā)爬蟲的第一步。第3章正則表達(dá)式與文件操作在爬蟲的開發(fā)80
通過這一章的學(xué)習(xí),你將會掌握如下知識。(1)正則表達(dá)式的基本符號。(2)如何在Python中使用正則表達(dá)式。(3)正則表達(dá)式的提取技巧。(4)Python讀寫文本文件和CSV文件。通過這一章的學(xué)習(xí),你將會掌握如下知識813.1正則表達(dá)式
正則表達(dá)式(RegularExpression)是一段字符串,它可以表示一段有規(guī)律的信息。Python自帶一個正則表達(dá)式模塊,通過這個模塊可以查找、提取、替換一段有規(guī)律的信息。
在程序開發(fā)中,要讓計算機(jī)程序從一大段文本中找到需要的內(nèi)容,就可以使用正則表達(dá)式來實現(xiàn)。
使用正則表達(dá)式有如下步驟。(1)尋找規(guī)律。(2)使用正則符號表示規(guī)律。(3)提取信息。3.1正則表達(dá)式正則表達(dá)式(Regul821.點號“.”
一個點號可以代替除了換行符以外的任何一個字符,包括但不限于英文字母、數(shù)字、漢字、英文標(biāo)點符號和中文標(biāo)點符號。2.星號“*”
一個星號可以表示它前面的一個子表達(dá)式(普通字符、另一個或幾個正則表達(dá)式符號)0次到無限次。3.1.1正則表達(dá)式的基本符號1.點號“.”3.1.1正則表達(dá)式的基本符號833.問號“?”
問號表示它前面的子表達(dá)式0次或者1次。注意,這里的問號是英文問號。
4.反斜杠“\”
反斜杠在正則表達(dá)式里面不能單獨使用,甚至在整個Python里都不能單獨使用。反斜杠需要和其他的字符配合使用來把特殊符號變成普通符號,把普通符號變成特殊符號。3.問號“?”84
反斜杠不僅可以把特殊符號變成普通符號,還可以把普通符號變成特殊符號。
例如“n”只是一個普通的字母,但是“\n”代表換行符。
在Python開發(fā)中,經(jīng)常遇到的轉(zhuǎn)義字符,如表3-1所示。反斜杠不僅可以把特殊符號變成普通符號,還可85轉(zhuǎn)義字符意義\n換行符\t制表符\\普通的反斜杠\'單引號\"雙引號\d數(shù)字
表3-1常見的轉(zhuǎn)義字符轉(zhuǎn)義字符意義\n換行符\t制表符\\普通的反斜杠\'單引號\865.?dāng)?shù)字“\d”
正則表達(dá)式里面使用“\d”來表示一位數(shù)字。為什么要用字母d呢?因為d是英文“digital(數(shù)字)”的首字母。
再次強(qiáng)調(diào)一下,“\d”雖然是由反斜杠和字母d構(gòu)成的,但是要把“\d”看成一個正則表達(dá)式符號整體。
6.小括號“()”
小括號可以把括號里面的內(nèi)容提取出來。5.?dāng)?shù)字“\d”873.1.2在Python中使用正則表達(dá)式Python已經(jīng)自帶了一個功能非常強(qiáng)大的正則表達(dá)式模塊。使用這個模塊可以非常方便地通過正則表達(dá)式來從一大段文字中提取有規(guī)律的信息。Python的正則表達(dá)式模塊名字為“re”,也就是“regularexpression”的首字母縮寫。在Python中需要首先導(dǎo)入這個模塊再進(jìn)行使用。導(dǎo)入的語句為:importre3.1.2在Python中使用正則表達(dá)式Pyt881.findallPython的正則表達(dá)式模塊包含一個findall方法,它能夠以列表的形式返回所有滿足要求的字符串。
findall的函數(shù)原型為:re.findall(pattern,string,flags=0)pattern表示正則表達(dá)式,string表示原來的字符串,flags表示一些特殊功能的標(biāo)志。
1.findall89findall的結(jié)果是一個列表,包含了所有的匹配到的結(jié)果。如果沒有匹配到結(jié)果,就會返回空列表,如圖3-1所示。圖3-1findall返回的內(nèi)容findall的結(jié)果是一個列表,包含了所有90
當(dāng)需要提取某些內(nèi)容的時候,使用小括號將這些內(nèi)容括起來,這樣才不會得到不相干的信息。如果包含多個“(.*?)”怎么返回呢?如圖3-2所示,返回的仍然是一個列表,但是列表里面的元素變?yōu)榱嗽M,元組里面的第1個元素是賬號,第2個元素為密碼。圖3-2多個括號內(nèi)的內(nèi)容會以元組形式返回當(dāng)需要提取某些內(nèi)容的時候,使用小括號將這些91
請注意代碼中的冒號和逗號,圖3-1代碼中為中文冒號和中文逗號;圖3-2代碼中為英文冒號和英文逗號。在實際使用正則表達(dá)式的過程中,中英文標(biāo)點符號混淆常常會導(dǎo)致各種問題。特別是冒號、逗號和引號,雖然中英文看起來非常相似,但實際上中文冒號和英文冒號是不一樣的,中文逗號和英文逗號也是不一樣的。
在某些字體里面,這種差異甚至無法察覺,因此在涉及正則表達(dá)式中的標(biāo)點符號時,最好直接復(fù)制粘貼,而不要手動輸入。請注意代碼中的冒號和逗號,圖3-1代碼中為中92
函數(shù)原型中有一個flags參數(shù)。這個參數(shù)是可以省略的。當(dāng)不省略的時候,具有一些輔助功能,例如忽略大小寫、忽略換行符等。這里以忽略換行符為例來進(jìn)行說明,如圖3-3所示。圖3-3使用re.S作為flag來忽略換行符函數(shù)原型中有一個flags參數(shù)。這個參數(shù)是93
在爬蟲的開發(fā)過程中非常容易出現(xiàn)這樣的情況,要匹配的內(nèi)容存在換行符“\n”。要忽略換行符,就需要使用到“re.S”這個flag。雖然說匹配到的結(jié)果中出現(xiàn)了“\n”這個符號,不過總比什么都得不到強(qiáng)。內(nèi)容里面的換行符在后期清洗數(shù)據(jù)的時候把它替換掉即可。在爬蟲的開發(fā)過程中非常容易出現(xiàn)這樣的情況,942.searchsearch()的用法和findall()的用法一樣,但是search()只會返回第1個滿足要求的字符串。一旦找到符合要求的內(nèi)容,它就會停止查找。對于從超級大的文本里面只找第1個數(shù)據(jù)特別有用,可以大大提高程序的運(yùn)行效率。
search()的函數(shù)原型為:re.search(pattern,string,flags=0)2.search95
對于結(jié)果,如果匹配成功,則是一個正則表達(dá)式的對象;如果沒有匹配到任何數(shù)據(jù),就是None。
如果需要得到匹配到的結(jié)果,則需要通過.group()這個方法來獲取里面的值,如圖3-4所示。圖3-4使用.group()來獲取search()方法找到的結(jié)果對于結(jié)果,如果匹配成功,則是一個正則表達(dá)式96
只有在.group()里面的參數(shù)為1的時候,才會把正則表達(dá)式里面的括號中的結(jié)果打印出來。.group()的參數(shù)最大不能超過正則表達(dá)式里面括號的個數(shù)。參數(shù)為1表示讀取第1個括號中的內(nèi)容,參數(shù)為2表示讀取第2個括號中的內(nèi)容,以此類推,如圖3-5所示。
只有在.group()里面的參數(shù)為1的時候,97圖3-5.group()的參數(shù)意義圖3-5.group()的參數(shù)意義983.“.*”和“.*?”的區(qū)別
在爬蟲開發(fā)中,.*?這3個符號大多數(shù)情況下一起使用。
點號表示任意非換行符的字符,星號表示匹配它前面的字符0次或者任意多次。所以“.*”表示匹配一串任意長度的字符串任意次。這個時候必須在“.*”的前后加其他的符號來限定范圍,否則得到的結(jié)果就是原來的整個字符串。
如果在“.*”的后面加一個問號,變成“.*?”,那么可以得到什么樣的結(jié)果呢?問號表示匹配它前面的符號0次或者1次。于是.*?的意思就是匹配一個能滿足要求的最短字符串。
3.“.*”和“.*?”的區(qū)別99
這樣說起來還是非常抽象,下面通過一個實際的例子來進(jìn)行說明。請看下面這一段話:我的微博密碼是:1234567,QQ密碼是:33445566,銀行卡密碼是:888888,Github密碼是:999abc999,幫我記住它們
這段話有一個顯著的規(guī)律,即密碼是:xxxxxx,”,也就是在“密碼是”這3個漢字的后面跟一個中文的冒號,冒號后面是密碼,密碼后面是中文的逗號。
這樣說起來還是非常抽象,下面通過一個實際的例100
如果想把這4個密碼提取出來,可以構(gòu)造以下兩個正則表達(dá)式:密碼是:(.*),密碼是:(.*?),
配合Python的findall方法,得到結(jié)果如圖3-6圖所示。
如果想把這4個密碼提取出來,可以構(gòu)造以下101圖3-6使用“.*”和“.*?”返回的結(jié)果圖3-6使用“.*”和“.*?”返回的結(jié)果102
使用“(.*)”得到的是只有一個元素的列表,里面是一個很長的字符串。
使用第2個正則表達(dá)式“(.*?)”,得到的結(jié)果是包含4個元素的列表,每個元素直接對應(yīng)原來文本中的每個密碼。
一句話總結(jié)如下。①“.*”:貪婪模式,獲取最長的滿足條件的字符串。②“.*?”:非貪婪模式,獲取最短的能滿足條件的字符串。使用“(.*)”得到的是只有一個元素的列表1033.1.3正則表達(dá)式提取技巧
1.不需要compile網(wǎng)上很多人的文章中,正則表達(dá)式使用pile()這個方法,導(dǎo)致代碼變成下面這樣:importreexample_text='我是kingname,我的微博賬號是:kingname,密碼是:12345678,QQ賬號是:99999,密碼是:890abcd,銀行卡賬號是:000001,密碼是:654321,Github賬號是:99999@,密碼是:7777love8888,請記住他們。'new_pattern=pile('賬號是:(.*?),密碼是:(.*?),',re.S)user_pass=re.findall(new_pattern,example_text)print(user_pass)3.1.3正則表達(dá)式提取技巧
1.不需要compile104這種寫法雖然結(jié)果正確,但純粹是畫蛇添足,是對Python的正則表達(dá)式模塊沒有理解透徹的體現(xiàn),是從其他啰嗦的編程語言中帶來的壞習(xí)慣。如果閱讀Python的正則表達(dá)式模塊的源代碼,就可以看出pile()是完全沒有必要的。對比pile()和re.findall()在源代碼中的寫法,如圖3-7所示的兩個方框。這種寫法雖然結(jié)果正確,但純粹是畫蛇添足,是對Pyt105圖3-7Python正則表達(dá)式模塊中的re.findall()和pile()圖3-7Python正則表達(dá)式模塊中的re.findal106
使用pile()的時候,程序內(nèi)部調(diào)用的是_compile()方法;當(dāng)使用re.finall()的時候,在模塊內(nèi)部自動先調(diào)用了_compile()方法,再調(diào)用findall()方法。re.findall()自帶pile()的功能,所以沒有必要使用pile()。Python3中正則表達(dá)式模塊的源代碼的入口文件為re.py。這個文件里面的注釋就是學(xué)習(xí)Python正則表達(dá)式模塊非常好的文檔,它包含了正則表達(dá)式各種符號的簡單說明和這個模塊內(nèi)部各個方法的使用,如圖3-8所示。
使用pile()的時候,程序內(nèi)部107圖3-8Pythonre.py文件自帶的文檔圖3-8Pythonre.py文件自帶的文檔1082.先抓大再抓小
一些無效內(nèi)容和有效內(nèi)容可能具有相同的規(guī)則。這種情況下很容易把有效內(nèi)容和無效內(nèi)容混在一起,如下面這段文字:
有效用戶:姓名:張三姓名:李四姓名:王五2.先抓大再抓小109無效用戶:姓名:不知名的小蝦米姓名:隱身的張大俠
有效用戶和無效用戶的名字前面都以“姓名:”開頭,如果使用“姓名:(.*?)\n”來進(jìn)行匹配,就會把有效信息和無效信息混在一起,難以區(qū)分,如圖3-9所示。無效用戶:110圖3-9使用“姓名:(.*?)\n”導(dǎo)致有效內(nèi)容和無效內(nèi)容混在一起圖3-9使用“姓名:(.*?)\n”導(dǎo)致有效內(nèi)容和無效111
要解決這個問題,就需要使用先抓大再抓小的技巧。先把有效用戶這個整體匹配出來,再從有效用戶里面匹配出人名,代碼和運(yùn)行效果如圖3-10所示。先抓大再抓小的思想會貫穿整個爬蟲開發(fā)過程,一定要重點掌握。圖3-10代碼和運(yùn)行效果要解決這個問題,就需要使用先抓大再抓小的技巧1123.括號內(nèi)和括號外
在上面的例子中,括號和“.*?”都是一起使用的,因此可能會有讀者認(rèn)為括號內(nèi)只能有這3種字符,不能有其他普通的字符。但實際上,括號內(nèi)也可以有其他字符,對匹配結(jié)果的影響如圖3-11所示。圖3-11括號里有無其他字符對匹配結(jié)果的影響3.括號內(nèi)和括號外圖3-11括號里有無其他字符對匹配結(jié)果1133.2Python文件操作Python的文件操作涉及對文件的讀/寫與編碼的處理,是學(xué)習(xí)爬蟲的必備知識。3.2.1使用Python讀/寫文本文件使用Python來讀/寫文本需要用到“open”這個關(guān)鍵字。它的作用是打開一個文件,并創(chuàng)建一個文件對象。使用Python打開文件,有兩種寫法。第1種方式如下:f=open('文件路徑','文件操作方式',encoding='utf-8')對文件進(jìn)行操作f.close()3.2Python文件操作Python的文件操114第2種方式,使用Python的上下文管理器:withopen('文件路徑','文件操作方式',encoding='utf-8')asf:
對文件進(jìn)行操作第1種方式需要手動關(guān)閉文件,但是在程序開發(fā)中經(jīng)常會出現(xiàn)忘記關(guān)閉文件的情況。第2種方法不需要手動關(guān)閉文件,只要代碼退出了縮進(jìn),Python就會自動關(guān)閉文件。第2種方式,使用Python的上下文管理器:1151.使用Python讀文本文件
使用Python打開一個文本文件時,首先要保證這個文件是存在的。在讀文件的時候,“文件操作方式”這個參數(shù)可以省略,也可以寫成“r”,也就是read的首字母。
文件路徑可以是絕對路徑,也可以是相對路徑。如果是絕對路徑,Linux和MacOS不能直接使用“~”表示“home目錄”,因為Python不認(rèn)識“~”這個符號。如果非要使用這個符號,需要使用Python的“os”模塊,代碼如下:importosreal_path=os.path.expanduser('~/project/xxx')1.使用Python讀文本文件116
這樣,Python就會將這種風(fēng)格的路徑轉(zhuǎn)化為Python能認(rèn)識的絕對路徑。
相對路徑是文本文件相對于現(xiàn)在的工作區(qū)而言的路徑,并不總是相對于當(dāng)前正在運(yùn)行的這個Python文件的路徑。在本章中,請讀者直接將文本文件和Python文件放在一起,這樣就可以直接使用文件名來打開文本文件。
文本文件的內(nèi)容和它相對于.py文件的位置如圖3-12所示。這樣,Python就會將這種風(fēng)格的路徑轉(zhuǎn)化為117圖3-12文本文件的內(nèi)容和它相對于.py文件的位置圖3-12文本文件的內(nèi)容和它相對于.py文件的位置118
使用下面的代碼來打開text.txt文件:withopen('text.txt',encoding='utf-8')asf:通過f來讀文件
這里有一個參數(shù)“encoding”。這個參數(shù)特別有用,它可以在打開文件的時候?qū)⑽募D(zhuǎn)換為UTF-8編碼格式,從而避免亂碼的出現(xiàn)。這個參數(shù)只有Python3有,在Python2中使用這個參數(shù)會報錯。如果文件是在Windows中創(chuàng)建的,并且使用UTF-8打開文件出現(xiàn)了亂碼,可以把編碼格式改為GBK。使用下面的代碼來打開text.txt文件:119
文本文件可以按行讀取,也可以直接讀取里面的所有內(nèi)容。
讀取所有行,并以列表的形式返回結(jié)果,代碼如下:
f.readlines()
運(yùn)行效果如圖3-13所示。
圖3-13使用readlines()讀取文本所有行并以列表形式返回結(jié)果文本文件可以按行讀取,也可以直接讀取里面的120
直接把文件里面的全部內(nèi)容用一個字符串返回,代碼如下:f.read()
運(yùn)行結(jié)果如圖3-14所示。圖3-14直接把整個文本內(nèi)容以一個字符串方式返回的結(jié)果直接把文件里面的全部內(nèi)容用一個字符串返回,代1212.使用Python寫文本文件
使用Python寫文件也需要先打開文件,使用如下代碼來打開文件:withopen('new.txt','w',encoding='utf-8')asf:通過f來寫文件
這里多出來一個參數(shù)“w”,w是英文write的首字母,意思是以寫的方式打開文件。這個參數(shù)除了為“w”外,還可以為“a”。它們的區(qū)別在于,如果原來已經(jīng)有一個new.txt文件了,使用“w”會覆蓋原來的文件,導(dǎo)致原來的內(nèi)容丟失;而使用“a”,則會把新的內(nèi)容寫到原來的文件末尾。2.使用Python寫文本文件122
寫文件時可以直接寫一大段文本,也可以寫一個列表。
直接將一大段字符串寫入到文本中,可以使用下面這一行代碼:f.write("一大段文字")
把列表里面的所有字符串寫入到文本中,可以使用下面這一行代碼:f.writelines(['第一段話','第二段話','第三段話'])寫文件時可以直接寫一大段文本,也可以寫一123
需要特別注意,寫列表的時候,Python寫到文本中的文字是不會自動換行的,需要人工輸入換行符才可以。代碼和運(yùn)行生成的文本new.txt如圖3-15和圖3-16所示。請注意代碼第8行列表中的兩個字符串,在new.txt的第3行中被拼在了一起。圖3-15寫字符串和包含字符串的列表到文本中的代碼需要特別注意,寫列表的時候,Python寫124圖3-16寫文本生成的文件內(nèi)容結(jié)果圖3-16寫文本生成的文件內(nèi)容結(jié)果1253.2.2使用Python讀/寫CSV文件CSV文件可以用Excel或者Numbers打開,得到可讀性很高的表格,如圖3-17所示。圖3-17使用Numbers打開CSV文件3.2.2使用Python讀/寫CSV文件C126CSV文件本質(zhì)上就是文本文件,但是如果直接用文本編輯器打開,可讀性并不高,如圖3-18所示。圖3-18直接用文本編輯器打開CSV文件CSV文件本質(zhì)上就是文本文件,但是如果直接127Python自帶操作CSV的模塊。使用這個模塊,可以將CSV文件的內(nèi)容轉(zhuǎn)換為Python的字典,從而方便使用。1.Python讀CSV文件
要讀取CSV文件,首先需要導(dǎo)入Python的CSV模塊:importcsvPython自帶操作CSV的模塊。使用這個128
由于CSV文件本質(zhì)上是一個文本文件,所以需要先以文本文件的方式打開,再將文件對象傳遞給CSV模塊:withopen('result.csv',encoding='utf-8')asf:reader=csv.DictReader(f)forrowinreader:
print(row)
運(yùn)行結(jié)果圖3-19所示。由于CSV文件本質(zhì)上是一個文本文件,所以需129圖3-19使用CSV模塊打開CSV文件圖3-19使用CSV模塊打開CSV文件130
代碼中,for循環(huán)得到的row是OrderedDict(有序字典),可以直接像普通字典那樣使用:username=row['username']content=row['content']reply_time=row['reply_time']
運(yùn)行結(jié)果如圖3-20所示。
代碼中,for循環(huán)得到的row是Order131圖3-20像讀字典一樣讀CSV文件圖3-20像讀字典一樣讀CSV文件132
短短幾行代碼,已經(jīng)將CSV文件轉(zhuǎn)換為字典了。
特別注意:
讀取文本內(nèi)容的代碼必須放在縮進(jìn)內(nèi)部進(jìn)行,否則會導(dǎo)致報錯,如圖3-21所示。圖3-21讀取文本內(nèi)容的代碼必須放在縮進(jìn)的里面短短幾行代碼,已經(jīng)將CSV文件轉(zhuǎn)換為字典了133
這是因為f變量里面的值是一個生成器,生成器只有在被使用(更準(zhǔn)確的說法是被迭代)的時候才會去讀文本內(nèi)容。但是退出with的縮進(jìn)以后,文件就被Python關(guān)閉了,這個時候當(dāng)然什么都讀不了。
那有沒有什么辦法可以繞過這個限制呢?當(dāng)然是有的,那就是使用列表推導(dǎo)式。圖3-22所示為使用列表推導(dǎo)式讀取文本內(nèi)容。請對比圖3-21和圖3-22第4行的不同。這是因為f變量里面的值是一個生成器,生成器只134圖3-22使用列表推導(dǎo)式讀取文本內(nèi)容圖3-22使用列表推導(dǎo)式讀取文本內(nèi)容1352.Python寫CSV文件Python可以把一個字典寫成CSV文件,或者把一個包含字典的列表寫成CSV文件。Python寫CSV文件比讀CSV文件稍微復(fù)雜一點,因為要指定列名。列名要和字典的Key一一對應(yīng)。
Python寫CSV文件時需要用到csv.DictWriter()這個類。它接收兩個參數(shù):第1個參數(shù)是文件對象f;第2個參數(shù)名為fieldnames,值為字典的Key列表。
寫入CSV文件的列名行:
writer.writeheader()2.Python寫CSV文件136
將包含字典的列表全部寫入到CSV文件中:writer.writerows(包含字典的列表)
寫入一個包含字典的列表,每一個字典對應(yīng)
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 人教版七年級歷史下學(xué)期第二單元隋遼宋夏金元時期:民族關(guān)系發(fā)展和社會變化第3課時金與南宋對峙測試試題(含答案)
- 人教版七年級歷史下學(xué)期第三單元明清時期至鴉片戰(zhàn)爭前統(tǒng)一多民族封建國家的鞏固與發(fā)展第2課時明朝的對外關(guān)系測試試題(含答案)
- 牙科種釘機(jī)操作規(guī)程
- 高速切磨機(jī)操作規(guī)程
- 2025年諸城生物會考試題及答案
- 危重患者護(hù)理常規(guī)、搶救與生命支持操作技能、病情評估與安全防范練習(xí)試題及答案
- 2025年火災(zāi)演練面試題及答案
- 2025年駕照理論測試題及答案
- 2025年國土空間規(guī)劃意見試題及答案
- 2025年高中語文選擇性必修上冊第一單元知識清單
- 六年級下冊數(shù)學(xué)同步學(xué)堂
- 【電氣專業(yè)】15D501建筑物防雷設(shè)施安裝
- 通信施工安全生產(chǎn)培訓(xùn)(登高作業(yè)施工專題)
- 四位數(shù)乘四位數(shù)乘法題500道
- 企業(yè)生產(chǎn)管理-9S現(xiàn)場管理培訓(xùn)PPT課件教材講義
- 豬場趕豬方案
- 蕪湖瑞視達(dá)光學(xué)科技高清攝像頭研發(fā)生產(chǎn)項目環(huán)境影響報告表
- 企業(yè)風(fēng)險分級管控與隱患排查治理雙體系落地
- 職工代表大會代表登記表(格式)
- GB/T 27731-2011衛(wèi)生用品用離型紙
- 183-壓力計量器具檢定系統(tǒng)框圖
評論
0/150
提交評論