Python爬蟲開發(fā)從入門到實(shí)戰(zhàn)PPT完整全套教學(xué)課件_第1頁
Python爬蟲開發(fā)從入門到實(shí)戰(zhàn)PPT完整全套教學(xué)課件_第2頁
Python爬蟲開發(fā)從入門到實(shí)戰(zhàn)PPT完整全套教學(xué)課件_第3頁
Python爬蟲開發(fā)從入門到實(shí)戰(zhàn)PPT完整全套教學(xué)課件_第4頁
Python爬蟲開發(fā)從入門到實(shí)戰(zhàn)PPT完整全套教學(xué)課件_第5頁
已閱讀5頁,還剩1088頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

PythonCrawlerDevelopment

Python爬蟲開發(fā)從入門到實(shí)戰(zhàn)(微課版)第1章緒論第2章Python基礎(chǔ)第3章正則表達(dá)式與文件操作第4章簡(jiǎn)單的網(wǎng)頁爬蟲開發(fā)第5章高性能HTML內(nèi)容解析第6章Python與數(shù)據(jù)庫第7章異步加載與請(qǐng)求頭第8章模擬登錄與驗(yàn)證碼第9章抓包與中間人爬蟲第10章Android原生App爬蟲第11章Scrapy第12章Scrapy高級(jí)應(yīng)用第13章爬蟲開發(fā)中的法律和道德問題全套PPT課件第1章緒論

所謂爬蟲,其本質(zhì)是一種計(jì)算機(jī)程序,它的行為看起來就像是蜘蛛在網(wǎng)上面爬行一樣,順著互聯(lián)網(wǎng)這個(gè)“網(wǎng)”,一條線一條線地“爬行”。所以爬蟲在英文中又叫作“Spider”,正是蜘蛛這個(gè)單詞。

通過這一章的學(xué)習(xí),你將會(huì)掌握如下知識(shí)。(1)爬蟲是什么。(2)爬蟲可以做什么。(3)爬蟲開發(fā)中有哪些技術(shù)。1.1爬蟲數(shù)據(jù)爆炸有效獲得數(shù)據(jù)1.2爬蟲可以做什么1.2.1收集數(shù)據(jù)

爬蟲可以用來收集數(shù)據(jù)。這也是爬蟲最直接、最常用的使用方法。

由于爬蟲是一種程序,程序的運(yùn)行速度極快,而且不會(huì)因?yàn)樽鲋貜?fù)的事情就感覺到疲勞,因此使用爬蟲來獲取大量的數(shù)據(jù),就變得極其簡(jiǎn)單和快捷了。請(qǐng)看圖1-1和圖1-2,這是起點(diǎn)中文網(wǎng)的“玄幻頻道”和“奇幻頻道”頁面。圖1-1起點(diǎn)中文網(wǎng)的“玄幻頻道”頁面圖1-2起點(diǎn)中文網(wǎng)的“奇幻頻道”頁面

圖1-1和圖1-2所示的這兩個(gè)版面除了內(nèi)容不一樣外,其他地方完全一樣。只要爬蟲能爬取“玄幻頻道”,那么就能爬取“奇幻頻道”。

假設(shè)要把這兩個(gè)頁面的內(nèi)容都獲取下來,如果人工來操作,就需要對(duì)兩個(gè)頁面進(jìn)行復(fù)制及粘貼,做很多重復(fù)的工作。而如果使用爬蟲,那么只需要開發(fā)“玄幻頻道”的爬蟲就能實(shí)現(xiàn)既能爬取“玄幻頻道”又能爬取“奇幻頻道”的目標(biāo)。

正是由于現(xiàn)在的網(wǎng)站大量使用了模板來生成頁面,所以爬蟲才能夠有用武之地。1.2.2盡職調(diào)查所謂的盡職調(diào)查,一般是指投資人在投資一個(gè)公司之前,需要知道這個(gè)公司是否如他們自己所描述的一樣盡職盡責(zé)地工作,是否有偷奸?;?、篡改數(shù)據(jù)、欺騙投資人的嫌疑。在過去,盡職調(diào)查一般通過調(diào)查目標(biāo)公司的客戶或者審計(jì)財(cái)務(wù)報(bào)表來實(shí)現(xiàn)。而有了爬蟲以后,要做盡職調(diào)查就方便很多了。

數(shù)據(jù)不會(huì)說謊,特別是數(shù)據(jù)量極大的數(shù)據(jù),人工偽造的總會(huì)和自然生成的存在區(qū)別。

而在以前,對(duì)于數(shù)據(jù)量極大的數(shù)據(jù)進(jìn)行搜集是一件非常困難的事情,但現(xiàn)在有了爬蟲的幫助,很多欺騙行為都會(huì)赤裸裸地暴露在陽光下。1.2.3刷流量和秒殺刷流量是爬蟲天然自帶的功能。當(dāng)爬蟲訪問了一個(gè)網(wǎng)站時(shí),如果這個(gè)爬蟲隱藏得很好,網(wǎng)站不能識(shí)別這一次訪問來自于爬蟲,那么就會(huì)把它當(dāng)成正常訪問。于是,爬蟲就“不小心”地刷了網(wǎng)站的訪問量。除了刷流量外,爬蟲也可以參與各種秒殺活動(dòng),包括但不限于在各種電商網(wǎng)站上搶商品,搶優(yōu)惠券,搶機(jī)票和火車票。

1.3爬蟲開發(fā)技術(shù)

爬蟲的開發(fā)有兩個(gè)層面。一個(gè)是“技”的層面,也就是各種語言和框架的使用。這種層面更像是軟件文檔,現(xiàn)在市面上大部分的爬蟲書籍還停留在這個(gè)層面。

而另一個(gè)層面是“術(shù)”的層面,遇到各種反爬蟲問題時(shí),應(yīng)該如何突破,如何隱藏爬蟲,如何模擬人的行為,以及遇到?jīng)]有見過的反爬蟲策略時(shí),應(yīng)該如何思考及如何使用爬蟲爬取非網(wǎng)頁內(nèi)容等。在“術(shù)”的層面,框架和工具都不是問題,用任何框架甚至Python自帶的模塊都能夠處理,“術(shù)”的層面更強(qiáng)調(diào)思想、流程和調(diào)度。

本書使用Python作為爬蟲的開發(fā)語言。由于Python具有語法簡(jiǎn)單、入門容易等特點(diǎn),現(xiàn)在已經(jīng)成為眾多領(lǐng)域的首選語言。

由于Python的語法接近原生的英語語法,因此只要能看懂單詞就能看懂Python代碼,這使得Python學(xué)習(xí)者能夠很容易地通過學(xué)習(xí)別人的代碼得到提高。

爬蟲的主要目的是獲取網(wǎng)頁內(nèi)容并解析。只要能達(dá)到這個(gè)目的,用什么方法都沒有問題。

關(guān)于獲取網(wǎng)頁,本書主要介紹了Python的兩個(gè)第三方模塊,一個(gè)是requests,另一個(gè)是爬蟲框架Scrapy。

關(guān)于解析網(wǎng)頁內(nèi)容,本書主要介紹了3種方式——正則表達(dá)式、XPath和BeautifulSoup。兩種網(wǎng)頁獲取方式和3種網(wǎng)頁解析方式可以自由搭配,隨意使用。

PythonCrawlerDevelopment

Python爬蟲開發(fā)從入門到實(shí)戰(zhàn)(微課版)第2章Python基礎(chǔ)Python(中文發(fā)音為派森,原意為蟒蛇,因此其圖標(biāo)為兩只蟒蛇)是一門高級(jí)程序開發(fā)語言。

所謂“高級(jí)程序開發(fā)語言”,是相對(duì)于“低級(jí)程序開發(fā)語言”來說的。

Python的語法接近正常的英語語法,因此即使不會(huì)編程,只要懂得基本的英語,也可以大致看懂Python代碼。

通過這一章的學(xué)習(xí),你將會(huì)掌握如下知識(shí)。(1)Python開發(fā)環(huán)境的搭建。(2)Python的基本知識(shí)、數(shù)據(jù)類型。(3)Python的條件語句和循環(huán)語句。(4)Python函數(shù)的定義和使用。(5)基于Python的面向?qū)ο缶幊檀a。

2.1Python的安裝和運(yùn)行

由于歷史原因,Python有兩個(gè)主要的大版本:Python2與Python3。這兩個(gè)大版本同時(shí)在往各自的方向發(fā)展。絕大多數(shù)的Python代碼在這兩個(gè)大版本中可以通用,但也有少數(shù)代碼只能在Python2中運(yùn)行,或者只能在Python3中運(yùn)行。Python官方曾經(jīng)宣布,在今后的發(fā)展中,Python3的升級(jí)會(huì)增加新功能,而Python2的升級(jí)只會(huì)做錯(cuò)誤修正,不會(huì)增加新的功能。Python之父吉多·范羅蘇姆(GuidovanRossum)建議使用Python3,并逐步淘汰Python2。Python官方推特宣布,在2020年停止維護(hù)Python2。本書所有代碼基于Python3開發(fā)。截至2017年4月,Python2正式版的最新版本為Python2.7.13,Python3正式版的最新版本為Python3.6.1。

Python的官方網(wǎng)站界面如圖2-1所示。2.1.1在Windows中安裝Python圖2-1Python官方網(wǎng)站界面

使用Windows操作系統(tǒng)的讀者,可訪問/ftp/python/3.6.1/python-3.6.1-amd64.exe下載Python3.6.1或者更高版本的安裝程序。

由于Python官方網(wǎng)站會(huì)受到某些干擾,所以在我國部分地區(qū)長(zhǎng)期無法訪問,在另一些地區(qū)間歇性無法訪問。如果以上網(wǎng)址無法訪問,各位讀者可稍后再嘗試。下載的文件名為python-3.6.1-amd64.exe。下載完成以后,雙擊這個(gè)安裝程序,安裝界面如圖2-2所示。圖2-2Python安裝界面

一定要勾選“AddPython3.6toPATH”復(fù)選框,這一點(diǎn)非常重要。然后選擇“InstallNow”選項(xiàng),即可開始安裝Python3.6.1。安裝完成以后,按“Win+R”組合鍵(“Win鍵”是鍵盤上像漢字“田”的那個(gè)鍵),在彈出的“運(yùn)行”對(duì)話框中輸入“cmd”(不包括最外層雙引號(hào),下同),如圖2-3所示。圖2-3在“運(yùn)行”對(duì)話框輸入“cmd”

單擊“確定”按鈕,打開Windows命令提示符(CommandPrompt,CMD)窗口,如圖2-4所示。

圖2-4Windows命令提示符窗口

輸入“python”并按下鍵盤上的回車鍵,如果CMD窗口顯示信息如圖2-5所示,表明Python安裝成功,并進(jìn)入了Python交互環(huán)境。圖2-5啟動(dòng)Python交互模式成功

在圖2-5中,出現(xiàn)了3個(gè)向右的箭頭“>>>”,這是提示用戶輸入內(nèi)容。在本章以及后面章節(jié)中的代碼中如果有這樣的3個(gè)箭頭,表示代碼就是在圖2-5所示的窗口中直接輸入的。例如:>>>1+12

這兩行代碼表示把“1+1”通過鍵盤輸入到這個(gè)Python交互環(huán)境中,然后按下回車鍵,下面不帶3個(gè)箭頭的數(shù)字“2”表示Python交互環(huán)境輸出的內(nèi)容。2.1.2在MacOS中安裝PythonMacOS系統(tǒng)自帶Python2。對(duì)于Python3,有兩種不同的安裝方法。如果有編程基礎(chǔ),或者會(huì)使用Homebrew,可以通過Homebrew安裝Python3,其安裝命令為:brewinstallpython3由于Homebrew在我國部分地區(qū)會(huì)受到一些干擾,要解決這個(gè)問題需要一些技術(shù)基礎(chǔ),所以對(duì)于沒有編程基礎(chǔ)或者沒有Homebrew的讀者,可以訪問/ftp/python/3.6.1/python-3.6.1-macosx10.6.pkg,下載Python3的安裝包。

2.1.3在Linux中安裝PythonUbuntu16.04或者更高版本的系統(tǒng)自帶了Python3.5.1或者更高版本的Python。這個(gè)版本的Python可以正常運(yùn)行本書所有的代碼,因此使用Ubuntu16.04或者以上系統(tǒng)的讀者可以跳過這一節(jié)。如果使用較低版本的Ubuntu,系統(tǒng)自帶Python2。某些系統(tǒng)可能只帶Python3.4.x。這里的x是一個(gè)數(shù)字,隨系統(tǒng)安裝時(shí)間的不同而不同。讀者可以在終端里輸入以下代碼查看系統(tǒng)自帶的Python3的版本:python3--version如果返回類似于Python3.4.3的結(jié)果,就表示系統(tǒng)確實(shí)自帶Python3.4.x。這種情況下,就需要單獨(dú)安裝Python3.6。

如果Ubuntu版本為16.04,直接在終端中輸入以下幾條命令來安裝Python3.6.1即可:sudoadd-apt-repositoryppa:fkrull/deadsnakessudoapt-getupdatesudoapt-getinstallpython3.6python3-devpython3-piplibxml2-devlibxslt1-devzlib1g-devlibffi-dev

libssl-dev如果系統(tǒng)為16.10或者17.04,那么安裝Python3.6非常簡(jiǎn)單,不需要添加軟件源,直接使用“apt-get”安裝即可:sudoapt-getupdatesudoapt-getinstallpython3.6python3-devpython3-piplibxml2-devlibxslt1-devzlib1g-devlibffi-dev

libssl-dev2.2Python開發(fā)環(huán)境2.2.1PyCharm介紹與安裝本書使用的集成開發(fā)環(huán)境為JetBrains公司的PyCharm。

PyCharm在Windows、MacOS和Linux中均有安裝文件。網(wǎng)站提供了社區(qū)版(CommunityEdition)和專業(yè)版(ProfessionalEdition),其中,社區(qū)版對(duì)個(gè)人用戶是免費(fèi)的,而且提供的功能可以滿足本書的所有開發(fā)需求。在網(wǎng)站上根據(jù)自己的操作系統(tǒng)選擇合適的版本,如圖2-6所示。圖2-6根據(jù)系統(tǒng)選擇PyCharm版本PyCharm的安裝非常簡(jiǎn)單,本書以安裝Windows版本為例來進(jìn)行說明。

首先從網(wǎng)站上下載PyCharm的安裝文件,然后雙擊安裝,在出現(xiàn)圖2-7所示界面時(shí),勾選“64-bitlauncher”復(fù)選框。除此之外,其余界面全部單擊“Next”按鈕,最后單擊“Install”按鈕進(jìn)行安裝。

安裝完成,第一次運(yùn)行,可以看到圖2-8所示的對(duì)話框。該對(duì)話框詢問是否導(dǎo)入已有設(shè)置。圖2-7勾選“64-bitlauncher”復(fù)選框

圖2-8第一次運(yùn)行PyCharm會(huì)詢問是否導(dǎo)入已有設(shè)置

由于是第一次安裝,因此直接單擊“OK”按鈕,出現(xiàn)用戶協(xié)議,如圖2-9所示。

閱讀完協(xié)議以后,單擊“Accept”按鈕,PyCharm將會(huì)正式運(yùn)行,并彈出主題選擇對(duì)話框,如圖2-10所示。

保持默認(rèn),直接單擊“OK”按鈕,開始創(chuàng)建工程。

圖2-9PyCharm用戶協(xié)議

圖2-10選擇PyCharm主題2.2.2運(yùn)行代碼

PyCharm是以工程為單位來管理代碼的,所以第一次運(yùn)行PyCharm的時(shí)候,它會(huì)問是創(chuàng)建一個(gè)工程還是打開一個(gè)工程。單擊“CreateNewProject”按鈕,填寫工程的路徑,如圖2-11所示。將這個(gè)路徑修改為一個(gè)熟悉的路徑,如“C:\MyProject\chapter2”。圖2-11填寫工程路徑PyCharm會(huì)自動(dòng)尋找Python的安裝位置,因此第二個(gè)下拉選項(xiàng)不需要修改,直接單擊“Create”按鈕,工程就創(chuàng)建好了。

工程創(chuàng)建好以后,進(jìn)入圖2-12所示的界面。

在左側(cè)窗格中右擊工程的文件夾名字,選擇“New”命令,在彈出的二級(jí)菜單中選擇“PythonFile”命令,如圖2-13所示。圖2-12工程初始化界面圖2-13選擇“New”-“PythonFile”命令

在彈出的對(duì)話框中輸入文件名,并單擊“OK”按鈕,Python文件(由于Python文件的擴(kuò)展名為“.py”,因此以下簡(jiǎn)稱“.py文件”)就創(chuàng)建好了,如圖2-14所示。圖2-14輸入.py文件名并單擊“OK”按鈕

創(chuàng)建完成.py文件以后,就可以在PyCharm中編輯Python代碼。Python代碼編寫完成以后,需要使用PyCharm來運(yùn)行代碼。單擊PyCharm右上角的灰色小箭頭圖標(biāo),選擇“EditConfigurations”選項(xiàng),如圖2-15所示。

在新打開的界面中單擊左上角的“+”號(hào),選擇Python選項(xiàng),如圖2-16所示。

圖2-15選擇“EditConfigurations”選項(xiàng)

圖2-16選擇“Python”選項(xiàng)

在彈出的對(duì)話框中,通過單擊箭頭所指的按鈕來選擇剛才創(chuàng)建的.py文件,并在“Name”文本框中輸入一個(gè)名字,這個(gè)名字可以任意填寫,中文及英文都可以,如圖2-17所示。圖2-17選擇剛才創(chuàng)建的.py文件并輸入名字

只需要修改這兩個(gè)地方即可,修改以后單擊“OK”按鈕。

對(duì)話框關(guān)閉以后,回到PyCharm的窗口,右上角出現(xiàn)了一個(gè)三角形按鈕和一個(gè)甲蟲按鈕,如圖2-18所示。單擊三角形按鈕可運(yùn)行代碼,單擊甲蟲按鈕可調(diào)試代碼。

現(xiàn)在單擊三角形按鈕,程序就運(yùn)行起來了,如圖2-19所示。

圖2-18三角形按鈕和甲蟲按鈕

圖2-19單擊三角形按鈕運(yùn)行程序2.3Python的數(shù)據(jù)結(jié)構(gòu)和控制結(jié)構(gòu)2.3.1整數(shù)、浮點(diǎn)數(shù)和變量1.整數(shù)與浮點(diǎn)數(shù)

Python里面的整數(shù)和數(shù)學(xué)里面的整數(shù)定義是一樣的,Python里面的浮點(diǎn)數(shù)可以看作是數(shù)學(xué)里面的小數(shù)。在Python中使用print函數(shù)打印一個(gè)整數(shù)或者浮點(diǎn)數(shù),可以看到這個(gè)整數(shù)或者浮點(diǎn)數(shù)被原樣打印了出來:>>>print(1234)1234>>>print(3.14159)3.14159

整數(shù)的加、減、乘可以直接在print中進(jìn)行,也可以通過括號(hào)來改變運(yùn)算的優(yōu)先級(jí):>>>print(1-10)-9>>>print(3+2-5*0)5>>>print((3+2-5)*0)0

在PyCharm中的運(yùn)行效果如圖2-20所示。圖2-20使用Python進(jìn)行加、減、乘運(yùn)算

上面的例子說到了整數(shù)的加、減、乘,那整數(shù)的除法呢?浮點(diǎn)數(shù)的加、減、乘、除呢?如果在Python中打印“0.1+0.2”的結(jié)果,會(huì)得到什么呢?例如下列代碼:>>>print(0.1+0.2)0.30000000000000004

結(jié)果并不是0.3,而是一個(gè)很長(zhǎng)的浮點(diǎn)數(shù)。這不是Python的問題,Java、C語言、C++等各種語言都有這個(gè)問題。這是由于計(jì)算機(jī)里面浮點(diǎn)數(shù)的儲(chǔ)存機(jī)制導(dǎo)致的。有興趣的讀者可以了解一下浮點(diǎn)數(shù)從十進(jìn)制轉(zhuǎn)化為二進(jìn)制的原理和結(jié)果。

由于這個(gè)原因,不應(yīng)該直接使用Python來進(jìn)行精確的計(jì)算,但是進(jìn)行日常的精度不高的四則運(yùn)算是沒有問題的,如圖2-21所示。

圖2-21使用Python進(jìn)行整數(shù)的除法和浮點(diǎn)數(shù)的

在圖2-21中,第7行使用#號(hào)開頭的內(nèi)容表示注釋,Python在運(yùn)行的時(shí)候會(huì)自動(dòng)忽略#號(hào)后面的內(nèi)容。2.變量

所謂變量,可以理解為一個(gè)存放其他數(shù)據(jù)的盒子。使用變量可以減少重復(fù)輸入。例如在Python中計(jì)算一個(gè)長(zhǎng)方體的底面積和體積,代碼如圖2-22所示。圖2-22在Python中計(jì)算長(zhǎng)方體的底面積和體積

在圖2-22的代碼中,變量在等號(hào)的左邊,變量里面將要存放的值在等號(hào)的右邊。等號(hào)是賦值的意思。將等號(hào)右邊的值賦給左邊的變量,這樣變量里面的值就等于右邊了。

而如果等號(hào)的右邊也是一個(gè)變量,那么就把等號(hào)右邊的變量里面的值賦給等號(hào)左邊的變量。2.3.2字符串、列表、元組1.字符串(String)在Python中,除了整數(shù)和浮點(diǎn)數(shù)外,還有字符串。任何被單引號(hào)或者雙引號(hào)括起來的內(nèi)容都可以認(rèn)為是字符串。字符串也可以賦值給變量。string_1='我是一個(gè)字符串'#字符串可以是中文或者任何其他語言string_2='Iamastring'string_3=''#空字符串string_4=''#空格string_5='a'#字符串可以只有一個(gè)字母string_6='123'#字符串型的數(shù)字string_7='我是字符串Iamastring12345'string_8="我是用雙引號(hào)括起來的字符串,我和單引號(hào)括起來的字符串沒有區(qū)別"

從上面的8行代碼中可以看到,字符串的內(nèi)容可以是中文,可以是英文,可以是數(shù)字,可以是空格,可以是中文、英文、數(shù)字和空格的組合。

需要注意的是,字符串形式的數(shù)字和普通的數(shù)字是不一樣的,它們不相等。例如如下代碼:string_6='123'int_variable=1232.列表(List)

列表是Python里面的容器之一,由方括號(hào)和方括號(hào)括起來的數(shù)據(jù)構(gòu)成。里面的數(shù)據(jù)可以是整數(shù)、浮點(diǎn)數(shù)、字符串,也可以是另一個(gè)列表或者其他的數(shù)據(jù)結(jié)構(gòu)。列表里面的每一項(xiàng)叫作列表的一個(gè)元素,每個(gè)元素之間使用英文逗號(hào)隔開:list_1=[1,2,3,4,5]#列表里面有5個(gè)元素,全部是數(shù)字list_2=['abc','x','','kkk']#列表里面有4個(gè)元素,全部是字符串list_3=[]#空列表list_4=[123,'xyz',3.14,[1,2,'yy']]#由多種元素組合起來的列表3.元組(Tuple)

元組是Python里面的容器之一,由小括號(hào)和小括號(hào)括起來的數(shù)據(jù)構(gòu)成。它的外型和列表非常像,只不過列表使用的是方括號(hào),元組使用的是小括號(hào)?!霸M”中的“元”和“二元一次方程”中的“元”是同一個(gè)意思,“組”就是組合的意思。tuple_1=(1,2,3,4,5)#元組里面有5個(gè)元素,全部為數(shù)字tuple_2=('abc','x','','kkk')#元組里面有4個(gè)元素,全部是字符串tuple_3=()#空元組tuple_4=(123,'xyz',[1,'t','z'],('o','pp'))#由多種元素組合起來的元組

元組和列表的區(qū)別:列表生成以后還可以往里面繼續(xù)添加數(shù)據(jù),也可以從里面刪除數(shù)據(jù);但是元組一旦生成就不能修改。如果它里面只有整數(shù)、浮點(diǎn)數(shù)、字符串、另一個(gè)元組,就既不能添加數(shù)據(jù),也不能刪除數(shù)據(jù),還不能修改里面數(shù)據(jù)的值。但是如果元組里面包含了一個(gè)列表,那么這個(gè)元組里面的列表依舊可以變化。2.3.3數(shù)據(jù)的讀取之所以要把字符串、列表和元組放在一起介紹,是因?yàn)榭梢允褂猛耆粯拥姆绞綇倪@3個(gè)數(shù)據(jù)結(jié)構(gòu)中讀取數(shù)據(jù),如圖2-23所示。圖2-23字符串、列表和元組的讀取方法完全相同1.指定下標(biāo)

在大多數(shù)編程語言里面,下標(biāo)都是從0開始的,Python也不例外。第0個(gè)元素就是指最左邊的元素。example_string='我是字符串'在字符串中,第0個(gè)字符是“我”字,第1個(gè)字符是“是”字,以此類推。example_list=['我','是','列','表']在列表中,第0個(gè)元素是“我”字,第1個(gè)元素是“是”字,以此類推。example_tuple=('我','是','元','組')

在元組中,第0個(gè)元素是“我”字,第1個(gè)元素是“是”字,以此類推。

在這3數(shù)據(jù)結(jié)構(gòu)中,想取任何一個(gè)元素,都可以直接使用:變量名[下標(biāo)]例如:>>>print(example_string[0])我>>>print(example_list[1])是>>>print(example_tuple[2])元-1表示最后一個(gè)元素,-2表示倒數(shù)第2個(gè)元素,-3表示倒數(shù)第3個(gè)元素,以此類推,所以:>>>print(example_string[-1])串>>>print(example_list[-2])列>>>print(example_tuple[-3])是2.切片操作

字符串切片以后的結(jié)果還是字符串,列表切片以后的結(jié)果還是列表,元組切片以后的結(jié)果還是元組。切片的格式為:變量名[開始位置下標(biāo):結(jié)束位置下標(biāo):步長(zhǎng)]

其中“開始位置下標(biāo)”“結(jié)束位置下標(biāo)”“步長(zhǎng)”可以部分省略,但是不能全部省略。這3個(gè)參數(shù)對(duì)應(yīng)的都是數(shù)字。切片的結(jié)果包括“開始位置下標(biāo)”所對(duì)應(yīng)的元素,但是不包括“結(jié)束位置下標(biāo)”所對(duì)應(yīng)的元素。

省略“開始位置下標(biāo)”,表示從下標(biāo)為0的元素開始計(jì)算。省略“結(jié)束位置下標(biāo)”,表示直到最后一個(gè)元素且包含最后一個(gè)元素。例如:>>>print(example_string[1:3])#讀取下標(biāo)為1和下標(biāo)為2的兩個(gè)字符是字>>>print(example_list[:3])#讀取下標(biāo)為0、1、2的3個(gè)元素我是列>>>print(example_tuple[2:])#讀取下標(biāo)為2的元素和它后面的所有元素元組

省略“開始位置下標(biāo)”和“結(jié)束位置下標(biāo)”,“步長(zhǎng)”取-1,表示倒序輸出,例如:>>>print(example_string[::-1])串符字是我3.拼接與修改

字符串與字符串之間可以相加,相加表示兩個(gè)字符串拼接起來。例如:>>>string_1='你好'>>>string_2='世界'>>>string_3=string_1+string_2>>>print(string_3)你好世界

元組與元組之間也可以相加,相加表示兩個(gè)元組拼接起來。例如:>>>tuple_1=('abc','xyz')>>>tuple_2=('哈哈哈哈','嘿嘿嘿嘿']>>>tuple_3=tuple_1+tuple_2>>>print(tuple_3)('abc','xyz','哈哈哈哈','嘿嘿嘿嘿')

列表與列表之間也可以相加,相加表示兩個(gè)列表拼接起來。例如:>>>list_1=['abc','xyz']>>>list_2=['哈哈哈哈','嘿嘿嘿嘿']>>>list_3=list_1+list_2>>>print(list_3)['abc','xyz','哈哈哈哈','嘿嘿嘿嘿']

特別的,可以通過列表的下標(biāo)來修改列表里面的值,格式為:變量名[下標(biāo)]=新的值例如:>>>existed_list=[1,2,3]>>>existed_list[1]='新的值'>>>print(existed_list)[1,'新的值',3]

列表還可以單獨(dú)在末尾添加元素,例如:>>>list_4=['Python','爬蟲']>>>print(list_4)['Python','爬蟲']>>>list_4.append('一')>>>print(list_4)['Python','爬蟲','一']>>>list_4.append('酷')>>>print(list_4)['Python','爬蟲','一','酷']

元組和字符串不能添加新的內(nèi)容,不能修改元組里面的非可變?nèi)萜髟兀膊荒苄薷淖址锩娴哪骋粋€(gè)字符。

字符串、列表和元組還有一些其他特性,它們之間的互相轉(zhuǎn)化將在爬蟲開發(fā)的過程中逐漸介紹。2.3.4字典與集合1.字典字典就是使用大括號(hào)括起來的鍵(Key)值(Value)對(duì)(Key-Value對(duì))。每個(gè)鍵值對(duì)之間使用英文逗號(hào)分隔,每個(gè)Key與Value之間使用英文冒號(hào)分隔。例如:dict_1={'superman':'超人是一個(gè)可以在天上飛的兩足獸','天才':'天才跑在時(shí)代的前面,把時(shí)代拖得氣喘吁吁。','xx':0,42:'42是一切的答案'}Key可以使用中文、英文或者數(shù)字,但是不能重復(fù)。Value可以是任意字符串、數(shù)字、列表、元組或者另一個(gè)字典,Value可以重復(fù)。

可以通過Key來從字典中讀取對(duì)應(yīng)的Value,有3種主要的格式:變量名[key]變量名.get(key)變量名.get(key,'在找不到key的情況下使用這個(gè)值')2.集合

集合是使用大括號(hào)括起來的各種數(shù)據(jù),可以看作沒有Value的字典。集合里面的元素不能重復(fù)。集合也是無序的。example_set={1,2,3,'a','b','c'}

集合最大的應(yīng)用之一就是去重。例如,把一個(gè)帶有重復(fù)元素的列表先轉(zhuǎn)換為集合,再轉(zhuǎn)換回列表,那么重復(fù)元素就只會(huì)保留一個(gè)。把列表轉(zhuǎn)換為集合需要使用set()函數(shù),把集合轉(zhuǎn)換為列表使用list()函數(shù):>>>duplicated_list=[3,1,3,2,4,6,6,7,'s','s','a']>>>unique_list=list(set(duplicated_list))>>>print(unique_list)[1,2,3,4,'s',6,7,'a']2.3.5條件語句1.if語句if這個(gè)關(guān)鍵字正如它的英文一樣,是“如果”的意思,即如果什么情況發(fā)生,就怎么樣。if的用法如下:if可以判斷真假的表達(dá)式或者是能被判斷是否為空的數(shù)據(jù)結(jié)構(gòu)在表達(dá)式的條件為真時(shí)運(yùn)行的代碼所有需要在if里面運(yùn)行的代碼都需要添加至少一個(gè)空格作為縮進(jìn),一般約定俗成用4個(gè)空格,從而方便人眼閱讀。一旦退出縮進(jìn),新的代碼就不再屬于這個(gè)if。2.短路效應(yīng)(1)在使用and連接的多個(gè)表達(dá)式中,只要有一個(gè)表達(dá)式不為真,那么后面的表達(dá)式就不會(huì)執(zhí)行。(2)在使用or連接的多個(gè)表達(dá)式中,只要有一個(gè)表達(dá)式為真,那么后面的表達(dá)式就不會(huì)執(zhí)行。

這個(gè)短路效應(yīng)有什么作用呢?來看看下面的代碼:name_list=[]ifname_listandname_list[100]=='張三':

print('OK')

從一個(gè)空列表里面讀下標(biāo)為100的元素,顯然會(huì)導(dǎo)致Python報(bào)錯(cuò),但是像上面這樣寫卻不會(huì)有任何問題。這是因?yàn)槿绻鹡ame_list為空,那么這個(gè)判斷直接就失敗了。根據(jù)短路效應(yīng),取第100個(gè)元素的操作根本就不會(huì)執(zhí)行,也就不會(huì)報(bào)錯(cuò)。只有這個(gè)列表里面至少有一個(gè)元素的時(shí)候,才會(huì)進(jìn)入第2個(gè)表達(dá)式“name_list[100]=='張三'”的判斷。3.多重條件判斷

對(duì)于多重條件的判斷,需要使用“if...elif...else...”。其中,“elif”可以有0個(gè),也可以有多個(gè),但是else只能有0個(gè)或者1個(gè)。例如下面的代碼:answer=2ifanswer==2:print('回答正確')else:print('回答錯(cuò)誤')

“if...else...”主要用于非此即彼的條件判斷。如果正確就執(zhí)行第3行代碼,如果錯(cuò)誤就執(zhí)行第5行代碼。第3行和第5行只會(huì)執(zhí)行其中之一,絕對(duì)不可能同時(shí)執(zhí)行。4.使用字典實(shí)現(xiàn)多重條件控制

如果有多個(gè)if,寫起來會(huì)很煩瑣,例如下面這一段代碼:ifstate=='start':

code=1elifstate=='running':

code=2elifstate=='offline':

code=3elifstate=='unknown':

code=4else:

code=5

使用“if...elif...else...”會(huì)讓代碼顯得冗長(zhǎng)。如果使用字典改寫,代碼就會(huì)變得非常簡(jiǎn)潔:state_dict={'start':1,'running':2,'offline':3,'unknown':4}code=state_dict.get(state,5)2.3.6for循環(huán)與while循環(huán)所謂循環(huán),就是讓一段代碼反復(fù)運(yùn)行多次。例如把“爬蟲”這個(gè)詞打印5次,讀者可能會(huì)先寫一行代碼,然后復(fù)制、粘貼:print('扒蟲')print('扒蟲')print('扒蟲')print('扒蟲')print('扒蟲')

但是粘貼完后才發(fā)現(xiàn)把“爬蟲”寫成了“扒蟲”,于是又要一行代碼一行代碼地去修改。這樣的寫法,不僅增加了大量重復(fù)的代碼,還會(huì)使維護(hù)和重構(gòu)變得很麻煩。為了解決這個(gè)問題,就有了循環(huán)。在上面的例子中,想把“爬蟲”打印5次,只需要兩行代碼:foriinrange(5):print('爬蟲')1.for循環(huán)for循環(huán)的常見寫法為:forxiny:循環(huán)體

先來看看Python獨(dú)有的for循環(huán)寫法。

從“可迭代”的對(duì)象中獲得每一個(gè)元素,代碼和運(yùn)行結(jié)果如圖2-24所示。圖2-24讀取列表中的每一個(gè)元素并打印

圖2-24所示的是for循環(huán)從列表中取出每一個(gè)元素。將列表換成元組或者集合再運(yùn)行代碼,可以發(fā)現(xiàn)效果一樣。for循環(huán)也可以直接從字符串里面獲得每一個(gè)字符,如圖2-25所示。圖2-25for循環(huán)讀取字符串里面的每一個(gè)字符

在做爬蟲的時(shí)候會(huì)遇到需要把列表展開的情況,常犯的一個(gè)錯(cuò)誤就是把字符串錯(cuò)當(dāng)成了列表展開。這個(gè)時(shí)候就會(huì)得到不正常的結(jié)果。for循環(huán)也可以把一個(gè)字典展開,得到里面的每一個(gè)Key,如圖2-26所示。

這個(gè)循環(huán)一共進(jìn)行了3輪,每一輪可以得到字典的一個(gè)Key。

再來看看幾乎所有編程語言中都有的寫法,如圖2-27所示。圖2-26for循環(huán)獲取字典每一個(gè)Key圖2-27最常見的按次數(shù)循環(huán)2.while循環(huán)while循環(huán)主要用在不知道循環(huán)需要執(zhí)行多少次的情況。這種情況下,要么讓程序永遠(yuǎn)運(yùn)行,要么在某個(gè)特定的條件下才結(jié)束,如圖2-28所示。圖2-28while循環(huán)運(yùn)行10次

圖2-28中代碼的意義為,如果i的值小于10,那么就進(jìn)入循環(huán),打印一句話,然后讓i增加1。使用while循環(huán)最常遇到的問題就是循環(huán)停不下來。如果忘記讓i增加1,那么i就會(huì)永遠(yuǎn)小于10,循環(huán)也就永遠(yuǎn)停不下來了。讀者可以把第4行代碼注釋以后運(yùn)行,看看會(huì)出現(xiàn)什么樣的效果。3.跳過本次循環(huán)與退出循環(huán)

在循環(huán)的運(yùn)行中,可能會(huì)遇到在某些時(shí)候不需要繼續(xù)執(zhí)行的情況,此時(shí)需要使用continue關(guān)鍵字來跳過本次循環(huán)。請(qǐng)看圖2-29所示的代碼運(yùn)行結(jié)果。

當(dāng)名字為“王五”的時(shí)候,跳過后面的代碼。continue只會(huì)影響到本次循環(huán),后面的循環(huán)不受影響。

當(dāng)遇到某些情況時(shí),需要結(jié)束整個(gè)循環(huán),這個(gè)時(shí)候需要使用break關(guān)鍵字。請(qǐng)看圖2-30所示的代碼。圖2-29使用continue跳過一次循環(huán)

圖2-30使用break提前結(jié)束整個(gè)循環(huán)while循環(huán)和for循環(huán)在使用continue和break的時(shí)候完全相同,請(qǐng)各位讀者自行測(cè)試。

特別注意:在循環(huán)里面還有循環(huán)(循環(huán)嵌套)的時(shí)候,continue和break都只對(duì)自己所在的這一層循環(huán)有效,不會(huì)影響外面的循環(huán)。2.4函數(shù)與類2.4.1函數(shù)1.什么是函數(shù)所謂的函數(shù),就是一套定義好的流程:輸入數(shù)據(jù),得到結(jié)果。在現(xiàn)實(shí)生活中,函數(shù)可以體現(xiàn)在方方面面。對(duì)廚師來講,每一個(gè)菜譜都是函數(shù);對(duì)農(nóng)民來講,每一種種菜的方法都是函數(shù);對(duì)建筑工人來講,每一個(gè)結(jié)構(gòu)的修建都是函數(shù);對(duì)司機(jī)來講,在不同路線上的駕駛方式也是函數(shù)……

兩個(gè)函數(shù)之間可能相互獨(dú)立,也可能一個(gè)函數(shù)的輸入是另一個(gè)函數(shù)的輸出,也可能在一個(gè)函數(shù)內(nèi)部調(diào)用另一個(gè)函數(shù)。2.函數(shù)的作用例2-1:現(xiàn)在想得到兩個(gè)房間在不同情況的溫度的統(tǒng)計(jì)信息,包括這兩個(gè)房間溫度的和、差、積、商、平均數(shù)。(1)不使用函數(shù)(2)使用函數(shù)3.定義函數(shù)

在Python里面,可使用def這個(gè)關(guān)鍵字來定義一個(gè)函數(shù)。一個(gè)函數(shù)的結(jié)構(gòu)一般如下:def函數(shù)名(參數(shù)1,參數(shù)2,參數(shù)3):

函數(shù)體第一行

函數(shù)體第二行

函數(shù)體第三行

函數(shù)體第n行

return返回值

一個(gè)函數(shù)可以有參數(shù),也可以沒有參數(shù)。如果沒有參數(shù),函數(shù)名后面為一對(duì)空括號(hào)。如果函數(shù)有參數(shù),參數(shù)可以有一個(gè),也可以有很多個(gè),參數(shù)可以是任何數(shù)據(jù)類型的。函數(shù)的參數(shù)甚至可以是另一個(gè)函數(shù)。

一個(gè)函數(shù)有至少一個(gè)返回值,可以人為指定返回任何類型的數(shù)據(jù)。如果沒有人為指定,那么返回值為None,返回值的個(gè)數(shù)可以是一個(gè),也可以是多個(gè)。函數(shù)的返回值可以是另一個(gè)函數(shù)。

一個(gè)函數(shù)可以沒有return語句,可以有一個(gè)return語句,也可以有多個(gè)return語句。圖2-31return后面的代碼

下面3種情況是等價(jià)的。(1)沒有return。(2)return(只有return,后面不跟任何變量)。(3)returnNone。

在函數(shù)中,可以使用return將里面的結(jié)果返回出來。代碼一旦運(yùn)行到了return,那么函數(shù)就會(huì)結(jié)束,return后面的代碼都不會(huì)被執(zhí)行。

請(qǐng)注意這里“return后面的代碼”的真正意思,如圖2-31所示。

在圖2-31所示的func_example_1()函數(shù)中:b=2+2print(b)

這兩行是return后面的代碼,這兩行代碼是永遠(yuǎn)不會(huì)被執(zhí)行的。

但是在圖2-31所示的func_example_2(x)這個(gè)函數(shù)中:elif0<x<=1:

returnx*10else:

return100

雖然第10行有一個(gè)return,但是第11~14行并不屬于“return后面的代碼”,因?yàn)椤癷f...elif...else...”形成了3條分支,只有每個(gè)分支內(nèi)部的return后面的代碼才不會(huì)被執(zhí)行,但是各個(gè)分支之間的return是互不影響的。由于代碼只能從上往下寫,所以第12行雖然寫在第10行后面,但是第12行在邏輯上其實(shí)是在第10行的旁邊,因此第12行是可能被執(zhí)行的。在邏輯上,每一個(gè)分支是并列的,如圖2-32所示。圖2-32分支在邏輯上是并列的

在一個(gè)Python工程中,應(yīng)該保證每個(gè)函數(shù)的名字唯一。函數(shù)體就是這個(gè)函數(shù)需要執(zhí)行的一系列操作。操作可能只有一行,也可能有很多行。

一個(gè)函數(shù)只做一件事情,Python編碼規(guī)范建議一個(gè)函數(shù)的函數(shù)體不超過20行代碼。如果超過了,說明這個(gè)函數(shù)做了不止一件事情,就應(yīng)該把這個(gè)函數(shù)拆分為更小的函數(shù)。這也就暗示了在函數(shù)體里面也可以調(diào)用其他的函數(shù)。4.調(diào)用函數(shù)例2-2:接收由用戶輸入的通過逗號(hào)分隔的兩個(gè)非零整數(shù),計(jì)算這兩個(gè)數(shù)字的和、差、積、商,并將結(jié)果返回給用戶。

問題分析:這個(gè)問題其實(shí)涉及3個(gè)相對(duì)獨(dú)立的過程。①得到用戶輸入的數(shù)據(jù)。②計(jì)算兩個(gè)數(shù)字的和、差、積、商。③將結(jié)果打印出來。

這3個(gè)過程可以定義成3個(gè)函數(shù),分別為如下。①get_input()。②calc(a,b)。③output(result)。(1)get_input()

這個(gè)函數(shù)沒有參數(shù),它負(fù)責(zé)接收用戶的輸入。這里用到了Python的input關(guān)鍵字,這個(gè)關(guān)鍵字可以接收用戶輸入的字符串,并將得到的字符串返回給一個(gè)變量。需要注意的是,input返回的一定是一個(gè)字符串,所以get_input()這個(gè)函數(shù)不僅需要接收輸入,還需要將輸入的形如'10,5'的字符串轉(zhuǎn)換為兩個(gè)整數(shù):10和5。(2)calc(a,b)

這個(gè)函數(shù)只負(fù)責(zé)計(jì)算。對(duì)它來說,a、b兩個(gè)參數(shù)就是兩個(gè)數(shù)字。它只需要計(jì)算這兩個(gè)數(shù)字的和、差、積、商,并將結(jié)果保存為一個(gè)字典返回即可。(3)output(result)

這個(gè)函數(shù)只負(fù)責(zé)輸出,將result這個(gè)字典中的值打印到屏幕上。

代碼運(yùn)行如圖2-33所示。

在圖中的代碼里面可以看到,3個(gè)函數(shù)是按順序獨(dú)立運(yùn)行的,后一個(gè)函數(shù)的輸入是前一個(gè)函數(shù)的輸出。數(shù)據(jù)流將3個(gè)函數(shù)連起來了。再來看圖2-34,運(yùn)行結(jié)果和上面的是完全一樣的,但是這里演示了在函數(shù)里面運(yùn)行另一個(gè)函數(shù)的情況。

通過以上示例說明:函數(shù)之間可以串行運(yùn)行,數(shù)據(jù)先由一個(gè)函數(shù)處理,再由另一個(gè)函數(shù)處理;函數(shù)也可以嵌套運(yùn)行,在一個(gè)函數(shù)里面調(diào)用另一個(gè)函數(shù)。當(dāng)然,在函數(shù)里面還可以定義函數(shù)。這就屬于比較高級(jí)的用法了,這里略去不講,有興趣的讀者可以閱讀Python的官方文檔。

圖2-33順序執(zhí)行函數(shù),接收用戶輸入并計(jì)算

圖2-34函數(shù)中調(diào)用函數(shù),接收用戶輸入并計(jì)算

5.函數(shù)的默認(rèn)參數(shù)

如果有參數(shù),定義函數(shù)的時(shí)候就需要把參數(shù)名都寫好。有時(shí)候會(huì)有這樣的情況:一個(gè)函數(shù)有很多的參數(shù),假設(shè)有5個(gè)參數(shù),其中4個(gè)參數(shù)在絕大多數(shù)情況下都是固定的4個(gè)值,只有極少數(shù)情況下需要手動(dòng)修改,于是稱這固定的4個(gè)值為這4個(gè)參數(shù)的默認(rèn)值。如果每次調(diào)用這個(gè)函數(shù)都要把這些默認(rèn)值帶上,就顯得非常麻煩。這種情況在Python開發(fā)中特別常見,尤其是在一些科學(xué)計(jì)算的第三方庫中。

在這段代碼中,兩個(gè)整數(shù)是以英文逗號(hào)來分隔的,那么可不可以使用其他符號(hào)來分隔呢?來看一下下面這段代碼:defget_input(split_char):

input_string=input('請(qǐng)輸入由{}分隔的兩個(gè)非零整數(shù):'.format(split_char))

a_string,b_string=input_string.split(split_char)

returnint(a_string),int(b_string)

來運(yùn)行一下這段代碼,這一次使用#號(hào)來分隔,如圖2-35所示。圖2-35使用#號(hào)分隔兩個(gè)數(shù)字

是否可以既能用英文逗號(hào)分隔,又可以用#號(hào)分隔,并且默認(rèn)情況下使用英文逗號(hào)分隔呢?如果每次調(diào)用這個(gè)函數(shù)的時(shí)候都必須寫成a,b=get_input(','),真的很麻煩,而且如果一不小心漏掉了這個(gè)參數(shù),還會(huì)導(dǎo)致程序報(bào)錯(cuò),如圖2-36所示。

圖2-36漏掉了函數(shù)參數(shù)導(dǎo)致報(bào)錯(cuò)

在Python里面,函數(shù)的參數(shù)可以有默認(rèn)值。當(dāng)調(diào)用函數(shù)的時(shí)候不寫參數(shù)時(shí),函數(shù)就會(huì)使用默認(rèn)參數(shù)。請(qǐng)看下面的代碼:defget_input_with_default_para(split_char=','):

input_string=input('請(qǐng)輸入由{}分隔的兩個(gè)非零整數(shù):'.format(split_char))

a_string,b_string=input_string.split(split_char)

returnint(a_string),int(b_string)

運(yùn)行效果如圖2-37所示。圖2-37調(diào)用帶有默認(rèn)參數(shù)的函數(shù)的運(yùn)行結(jié)果

如果調(diào)用函數(shù)get_input_with_default_para時(shí)不寫參數(shù),就會(huì)使用默認(rèn)的逗號(hào);如果帶上了參數(shù),那么就會(huì)使用這個(gè)參數(shù)對(duì)應(yīng)的符號(hào)來作為分隔符。

函數(shù)也可以有多個(gè)默認(rèn)參數(shù),例如如下的代碼:defprint_x_y_z(x=100,y=0,z=50):

print('x的值為{},y的值為{},z的值為{}'.format(x,y,z))

print_x_y_z(1,2,3)#直接寫上3個(gè)參數(shù),從左到右依次賦值print_x_y_z(6)#只寫一個(gè)值的時(shí)候,優(yōu)先賦值給左邊的參數(shù)print_x_y_z(y=-8)#也可以指定參數(shù)的名字,將值直接賦給指定的參數(shù)print_x_y_z(y='哈哈',x='嘿嘿')#如果指定了參數(shù)名,那么參數(shù)順序就無關(guān)緊要

運(yùn)行結(jié)果如圖2-38所示。

在調(diào)用函數(shù)的時(shí)候,如果指定了參數(shù)名,就會(huì)把值賦給這個(gè)參數(shù);如果沒有指定參數(shù)名,就會(huì)從左到右依次賦值給各個(gè)參數(shù)。圖2-38調(diào)用含有多個(gè)默認(rèn)參數(shù)的函數(shù)的運(yùn)行結(jié)果

6.Python函數(shù)的注意事項(xiàng)(1)函數(shù)參數(shù)的類型決定了它的作用范圍

函數(shù)外面的容器類作為參數(shù)傳遞到函數(shù)中以后,如果函數(shù)修改了這個(gè)容器里面的值,那么函數(shù)外面的容器也會(huì)受到影響。但是函數(shù)外面的普通變量作為參數(shù)傳遞到函數(shù)中,并且函數(shù)修改了這個(gè)參數(shù)的時(shí)候,外面的變量不受影響。

為了更好地理解這段話,請(qǐng)看圖2-39的運(yùn)行結(jié)果。在代碼中演示的容器類為列表,對(duì)字典和集合同樣適用。圖2-39函數(shù)可以修改容器類的數(shù)據(jù)

但不能修改普通變量(2)默認(rèn)參數(shù)陷阱

請(qǐng)看下面的代碼,并猜測(cè)其輸出:defdefault_para_trap(para=[],value=0):

para.append(value)

returnpara

print('第一步')print('函數(shù)返回值:{}'.format(default_para_trap(value=100)))print('第二步')print('函數(shù)返回值:{}'.format(default_para_trap(value=50)))實(shí)際情況如圖2-40所示。圖2-40實(shí)際運(yùn)行效果

運(yùn)行結(jié)果如圖2-41所示。

圖2-41修改后的運(yùn)行結(jié)果

在Python里面,一切都是對(duì)象。請(qǐng)看下面的代碼:a='abc,def'a_prefix,a_suffix=a.split(',')b=[1,2,3]b.append(4)b.extend([5,6,7])b.pop()c={'x':1,'y':2,'z':3}c.get('x')2.4.2類與面向?qū)ο缶幊?/p>

在上面的代碼中,出現(xiàn)了好幾個(gè)“xxx.yyy('zzz')”形式的語句,其中的“split”“append”“extend”“pop”“get”在面向?qū)ο缶幊讨薪凶饕粋€(gè)對(duì)象的“方法”。代碼中的“a”“a_prefix”“a_suffix”都是字符串對(duì)象,“b”是列表對(duì)象,“c”是字典對(duì)象。

對(duì)象有“屬性”和“方法”?!皩傩浴本褪敲枋鲞@個(gè)對(duì)象的各種標(biāo)簽,“方法”就是這個(gè)對(duì)象可以做的動(dòng)作。

對(duì)象可以只有屬性沒有方法,也可以只有方法沒有屬性。

首先要有類,才能有對(duì)象。

所以在Python以及其他支持面向?qū)ο蟮木幊陶Z言中,要?jiǎng)?chuàng)建每一個(gè)具體的對(duì)象,都需要先創(chuàng)建類。1.如何定義一個(gè)類

在Python中使用關(guān)鍵字“class”來定義一個(gè)類。類一般由以下元素構(gòu)成:類名;父類;初始化方法(在有些編程語言中叫作構(gòu)造函數(shù));屬性;方法。2.如何讀懂一個(gè)類

首先需要明白一點(diǎn),是否使用面向?qū)ο缶幊膛c代碼能否正常運(yùn)行沒有任何關(guān)系。使用面向?qū)ο缶幊袒蛘呤褂煤瘮?shù)都可以實(shí)現(xiàn)相同的功能。區(qū)別在于寫代碼、讀代碼和改代碼的“人”。面向?qū)ο缶幊痰淖饔檬欠奖愦a的開發(fā)和維護(hù)。

那么如何閱讀一個(gè)使用面向?qū)ο笏枷腴_發(fā)的程序呢?基本思路如下。①這個(gè)類有哪些屬性(看外貌)。②這個(gè)類有哪些方法(能做什么)。③這些方法在哪里被調(diào)用(做了什么)。④這些方法的實(shí)現(xiàn)細(xì)節(jié)(怎么做的)。2.5階段案例——猜數(shù)游戲2.5.1需求分析使用Python開發(fā)一個(gè)猜數(shù)小游戲。在游戲中,程序每一輪會(huì)隨機(jī)生成一個(gè)0~1024之間的數(shù)字,用戶輸入猜測(cè)的數(shù)字,程序告訴用戶猜大了還是猜小了。在一定次數(shù)內(nèi)猜對(duì),則本輪用戶獲勝,否則本輪用戶失敗。每一輪開始時(shí),程序會(huì)要求用戶輸入用戶名。程序會(huì)一直運(yùn)行,直到用戶輸入“3”,停止游戲。在每一輪游戲開始前,輸入“1”可以查看用戶的輸入歷史。1.知識(shí)點(diǎn)(1)隨機(jī)生成數(shù)字,涉及Python的隨機(jī)數(shù)模塊。(2)用戶輸入數(shù)字,程序輸出結(jié)果,涉及Python的輸入及輸出模塊。(3)程序會(huì)自動(dòng)開始下一輪,涉及Python的循環(huán)模塊。(4)判斷用戶的輸入,涉及Python的條件判斷。(5)查詢用戶的輸入歷史,涉及Python的字典和列表。2.提示

如何判斷每一輪猜測(cè)多少次以內(nèi)算猜測(cè)成功,多少次以上算猜測(cè)失???

根據(jù)二分法的原理,假設(shè)答案的范圍是M~N,那么最多猜測(cè)log2(M+N)次就能猜測(cè)出正確答案。在這個(gè)案例中,范圍為0~1024,以2為底,1024的對(duì)數(shù)為10,所以最多猜測(cè)10次就能得到正確答案。deftry_to_guess(name,answer):

try_num=0

whiletry_num<10:

guess_answer=int(input('請(qǐng)輸入一個(gè)數(shù)字:'))

ifguess_answer<answer:

print('你輸入的數(shù)字比正確答案小。')

elifguess_answer==answer:

print('回答正確!')

history[name].append('成功')

2.5.2核心代碼構(gòu)建

break

else:

print('你輸入的數(shù)字比正確答案大。')

try_num+=1

else:

print('猜錯(cuò)次數(shù)太多,失敗。')

history[name].append('失敗')2.5.3調(diào)試與運(yùn)行運(yùn)行以后的界面如圖2-43所示。輸入2繼續(xù)游戲,進(jìn)入游戲界面,用戶輸入數(shù)字進(jìn)行猜測(cè),如圖2-44所示。

圖2-43猜數(shù)游戲的啟動(dòng)界面

圖2-44猜數(shù)游戲的進(jìn)行畫面

猜測(cè)完成以后,無論成功還是失敗,都重新開始游戲。多次游戲以后,輸入1可查看歷史記錄,如圖2-45所示。圖2-45查看游戲歷史記錄2.6本章小結(jié)

本章首先講解了Python在Windows、MacOS和Linux中的安裝,以及Python集成開發(fā)環(huán)境PyCharm的安裝和使用。然后講到了Python的基礎(chǔ)知識(shí),包括Python的基本數(shù)據(jù)結(jié)構(gòu)和基本控制結(jié)構(gòu)。最后講到了函數(shù)和面向?qū)ο缶幊?。這些基本概念是學(xué)習(xí)爬蟲的基石,只有牢牢掌握了Python的基本知識(shí),才能更有效率地開發(fā)爬蟲。2.7動(dòng)手實(shí)踐

請(qǐng)修改階段案例中的程序,實(shí)現(xiàn)自定義答案的范圍。提示

在Python3中計(jì)算以2為底的某個(gè)數(shù)的對(duì)數(shù),使用如下兩行代碼:importmathmax_try_num=math.log2(1024)

PythonCrawlerDevelopment

Python爬蟲開發(fā)從入門到實(shí)戰(zhàn)(微課版)第3章正則表達(dá)式與文件操作

在爬蟲的開發(fā)中,需要把有用的信息從一大段文本中提取出來。正則表達(dá)式是提取信息的方法之一。

正則表達(dá)式雖然不是最簡(jiǎn)單的也不是最高效的數(shù)據(jù)提取方法,但它是最直接的。而且在某些情況下,只有使用正則表達(dá)式才能達(dá)到目的。學(xué)好正則表達(dá)式,是開發(fā)爬蟲的第一步。

通過這一章的學(xué)習(xí),你將會(huì)掌握如下知識(shí)。(1)正則表達(dá)式的基本符號(hào)。(2)如何在Python中使用正則表達(dá)式。(3)正則表達(dá)式的提取技巧。(4)Python讀寫文本文件和CSV文件。3.1正則表達(dá)式

正則表達(dá)式(RegularExpression)是一段字符串,它可以表示一段有規(guī)律的信息。Python自帶一個(gè)正則表達(dá)式模塊,通過這個(gè)模塊可以查找、提取、替換一段有規(guī)律的信息。

在程序開發(fā)中,要讓計(jì)算機(jī)程序從一大段文本中找到需要的內(nèi)容,就可以使用正則表達(dá)式來實(shí)現(xiàn)。

使用正則表達(dá)式有如下步驟。(1)尋找規(guī)律。(2)使用正則符號(hào)表示規(guī)律。(3)提取信息。1.點(diǎn)號(hào)“.”

一個(gè)點(diǎn)號(hào)可以代替除了換行符以外的任何一個(gè)字符,包括但不限于英文字母、數(shù)字、漢字、英文標(biāo)點(diǎn)符號(hào)和中文標(biāo)點(diǎn)符號(hào)。2.星號(hào)“*”

一個(gè)星號(hào)可以表示它前面的一個(gè)子表達(dá)式(普通字符、另一個(gè)或幾個(gè)正則表達(dá)式符號(hào))0次到無限次。3.1.1正則表達(dá)式的基本符號(hào)3.問號(hào)“?”

問號(hào)表示它前面的子表達(dá)式0次或者1次。注意,這里的問號(hào)是英文問號(hào)。

4.反斜杠“\”

反斜杠在正則表達(dá)式里面不能單獨(dú)使用,甚至在整個(gè)Python里都不能單獨(dú)使用。反斜杠需要和其他的字符配合使用來把特殊符號(hào)變成普通符號(hào),把普通符號(hào)變成特殊符號(hào)。

反斜杠不僅可以把特殊符號(hào)變成普通符號(hào),還可以把普通符號(hào)變成特殊符號(hào)。

例如“n”只是一個(gè)普通的字母,但是“\n”代表換行符。

在Python開發(fā)中,經(jīng)常遇到的轉(zhuǎn)義字符,如表3-1所示。轉(zhuǎn)義字符意義\n換行符\t制表符\\普通的反斜杠\'單引號(hào)\"雙引號(hào)\d數(shù)字

表3-1常見的轉(zhuǎn)義字符5.?dāng)?shù)字“\d”

正則表達(dá)式里面使用“\d”來表示一位數(shù)字。為什么要用字母d呢?因?yàn)閐是英文“digital(數(shù)字)”的首字母。

再次強(qiáng)調(diào)一下,“\d”雖然是由反斜杠和字母d構(gòu)成的,但是要把“\d”看成一個(gè)正則表達(dá)式符號(hào)整體。

6.小括號(hào)“()”

小括號(hào)可以把括號(hào)里面的內(nèi)容提取出來。3.1.2在Python中使用正則表達(dá)式Python已經(jīng)自帶了一個(gè)功能非常強(qiáng)大的正則表達(dá)式模塊。使用這個(gè)模塊可以非常方便地通過正則表達(dá)式來從一大段文字中提取有規(guī)律的信息。Python的正則表達(dá)式模塊名字為“re”,也就是“regularexpression”的首字母縮寫。在Python中需要首先導(dǎo)入這個(gè)模塊再進(jìn)行使用。導(dǎo)入的語句為:importre1.findallPython的正則表達(dá)式模塊包含一個(gè)findall方法,它能夠以列表的形式返回所有滿足要求的字符串。

findall的函數(shù)原型為:re.findall(pattern,string,flags=0)pattern表示正則表達(dá)式,string表示原來的字符串,flags表示一些特殊功能的標(biāo)志。

findall的結(jié)果是一個(gè)列表,包含了所有的匹配到的結(jié)果。如果沒有匹配到結(jié)果,就會(huì)返回空列表,如圖3-1所示。圖3-1findall返回的內(nèi)容

當(dāng)需要提取某些內(nèi)容的時(shí)候,使用小括號(hào)將這些內(nèi)容括起來,這樣才不會(huì)得到不相干的信息。如果包含多個(gè)“(.*?)”怎么返回呢?如圖3-2所示,返回的仍然是一個(gè)列表,但是列表里面的元素變?yōu)榱嗽M,元組里面的第1個(gè)元素是賬號(hào),第2個(gè)元素為密碼。圖3-2多個(gè)括號(hào)內(nèi)的內(nèi)容會(huì)以元組形式返回

請(qǐng)注意代碼中的冒號(hào)和逗號(hào),圖3-1代碼中為中文冒號(hào)和中文逗號(hào);圖3-2代碼中為英文冒號(hào)和英文逗號(hào)。在實(shí)際使用正則表達(dá)式的過程中,中英文標(biāo)點(diǎn)符號(hào)混淆常常會(huì)導(dǎo)致各種問題。特別是冒號(hào)、逗號(hào)和引號(hào),雖然中英文看起來非常相似,但實(shí)際上中文冒號(hào)和英文冒號(hào)是不一樣的,中文逗號(hào)和英文逗號(hào)也是不一樣的。

在某些字體里面,這種差異甚至無法察覺,因此在涉及正則表達(dá)式中的標(biāo)點(diǎn)符號(hào)時(shí),最好直接復(fù)制粘貼,而不要手動(dòng)輸入。

函數(shù)原型中有一個(gè)flags參數(shù)。這個(gè)參數(shù)是可以省略的。當(dāng)不省略的時(shí)候,具有一些輔助功能,例如忽略大小寫、忽略換行符等。這里以忽略換行符為例來進(jìn)行說明,如圖3-3所示。圖3-3使用re.S作為flag來忽略換行符

在爬蟲的開發(fā)過程中非常容易出現(xiàn)這樣的情況,要匹配的內(nèi)容存在換行符“\n”。要忽略換行符,就需要使用到“re.S”這個(gè)flag。雖然說匹配到的結(jié)果中出現(xiàn)了“\n”這個(gè)符號(hào),不過總比什么都得不到強(qiáng)。內(nèi)容里面的換行符在后期清洗數(shù)據(jù)的時(shí)候把它替換掉即可。2.searchsearch()的用法和findall()的用法一樣,但是search()只會(huì)返回第1個(gè)滿足要求的字符串。一旦找到符合要求的內(nèi)容,它就會(huì)停止查找。對(duì)于從超級(jí)大的文本里面只找第1個(gè)數(shù)據(jù)特別有用,可以大大提高程序的運(yùn)行效率。

search()的函數(shù)原型為:re.search(pattern,string,flags=0)

對(duì)于結(jié)果,如果匹配成功,則是一個(gè)正則表達(dá)式的對(duì)象;如果沒有匹配到任何數(shù)據(jù),就是None。

如果需要得到匹配到的結(jié)果,則需要通過.group()這個(gè)方法來獲取里面的值,如圖3-4所示。圖3-4使用.group()來獲取search()方法找到的結(jié)果

只有在.group()里面的參數(shù)為1的時(shí)候,才會(huì)把正則表達(dá)式里面的括號(hào)中的結(jié)果打印出來。.group()的參數(shù)最大不能超過正則表達(dá)式里面括號(hào)的個(gè)數(shù)。參數(shù)為1表示讀取第1個(gè)括號(hào)中的內(nèi)容,參數(shù)為2表示讀取第2個(gè)括號(hào)中的內(nèi)容,以此類推,如圖3-5所示。

圖3-5.group()的參數(shù)意義3.“.*”和“.*?”的區(qū)別

在爬蟲開發(fā)中,.*?這3個(gè)符號(hào)大多數(shù)情況下一起使用。

點(diǎn)號(hào)表示任意非換行符的字符,星號(hào)表示匹配它前面的字符0次或者任意多次。所以“.*”表示匹配一串任意長(zhǎng)度的字符串任意次。這個(gè)時(shí)候必須在“.*”的前后加其他的符號(hào)來限定范圍,否則得到的結(jié)果就是原來的整個(gè)字符串。

如果在“.*”的后面加一個(gè)問號(hào),變成“.*?”,那么可以得到什么樣的結(jié)果呢?問號(hào)表示匹配它前面的符號(hào)0次或者1次。于是.*?的意思就是匹配一個(gè)能滿足要求的最短字符串。

這樣說起來還是非常抽象,下面通過一個(gè)實(shí)際的例子來進(jìn)行說明。請(qǐng)看下面這一段話:我的微博密碼是:1234567,QQ密碼是:33445566,銀行卡密碼是:888888,Github密碼是:999abc999,幫我記住它們

這段話有一個(gè)顯著的規(guī)律,即密碼是:xxxxxx,”,也就是在“密碼是”這3個(gè)漢字的后面跟一個(gè)中文的冒號(hào),冒號(hào)后面是密碼,密碼后面是中文的逗號(hào)。

如果想把這4個(gè)密碼提取出來,可以構(gòu)造以下兩個(gè)正則表達(dá)式:密碼是:(.*),密碼是:(.*?),

配合Python的findall方法,得到結(jié)果如圖3-6圖所示。

圖3-6使用“.*”和“.*?”返回的結(jié)果

使用“(.*)”得到的是只有一個(gè)元素的列表,里面是一個(gè)很長(zhǎng)的字符串。

使用第2個(gè)正則表達(dá)式“(.*?)”,得到的結(jié)果是包含4個(gè)元素的列表,每個(gè)元素直接對(duì)應(yīng)原來文本中的每個(gè)密碼。

一句話總結(jié)如下。①“.*”:貪婪模式,獲取最長(zhǎng)的滿足條件的字符串。②“.*?”:非貪婪模式,獲取最短的能滿足條件的字符串。3.1.3正則表達(dá)式提取技巧

1.不需要compile網(wǎng)上很多人的文章中,正則表達(dá)式使用pile()這個(gè)方法,導(dǎo)致代碼變成下面這樣:importreexample_text='我是kingname,我的微博賬號(hào)是:kingname,密碼是:12345678,QQ賬號(hào)是:99999,密碼是:890abcd,銀行卡賬號(hào)是:000001,密碼是:654321,G

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

評(píng)論

0/150

提交評(píng)論