大家好,由於前天熬夜寫完第一篇博客,然後昨天又是沒休息好,昨天也就不想更新博客,就只是看了會資料就早點休息了,今天補上我這兩天的所學,先記錄一筆。我發現有時候我看的話會比較敷衍,而如果我寫出來(無論寫到筆記本中還是博客中,我都有不同的感覺)就會有不同的想法,我看書或者看資料有時候感覺就是有一種惰性, ...
大家好,由於前天熬夜寫完第一篇博客,然後昨天又是沒休息好,昨天也就不想更新博客,就只是看了會資料就早點休息了,今天補上我這兩天的所學,先記錄一筆。我發現有時候我看的話會比較敷衍,而如果我寫出來(無論寫到筆記本中還是博客中,我都有不同的感覺)就會有不同的想法,我看書或者看資料有時候感覺就是有一種惰性,得過且過的感覺,有時候一個知識想不通道不明,想了一會兒,就會找藉口給自己說這個知識不重要,不需要太糾結了,還是去看下一個吧,然後就如此往複下去,學習就會有漏洞,所以這更加堅定了我寫博客來記錄的想法。
上一篇博客我記錄了python的相關基礎編程知識,包括數據類型啊,變數啊,正則表達式啊等等,感覺這些基礎也沒什麼好說的,所以說我寫的也不是很詳細,最近兩天我寫了個小爬蟲並且接觸了python的oop編程,感覺今天還是有很多寫的,首先這個小爬蟲算是對正則表達式的一個小應用,爬蟲的基本原理我感覺就是用python中的庫或者第三方庫的先抓取網頁源代碼,解析出地址,然後在解析出的地址中用正則表達式篩選出我們想要的內容,比如我寫的就是一個簡單的抓取網頁的圖片信息。
一:爬蟲
寫爬蟲的話剛開始要先清楚步驟,然後把思維邏輯理清楚,再來寫代碼,感覺最後寫代碼只是思維的映射,最主要還是自己先搞清楚邏輯,閑話少說,接下來我們就進入正題。我在網上看到的一個csdn大牛的寫爬蟲心得是這樣講的,一段自動抓取互聯網信息的程式稱為爬蟲,主要組成:爬蟲調度器、URL管理器、網頁下載器、網頁解析器
(1)爬蟲調度器:程式的入口,主要負責爬蟲程式的控制
(2)URL管理器: 1、添加新的URL到代爬取集合
2、判斷待添加URL是否已存在
3、判斷是否還有待爬取的URL,將URL從待爬取集合移動到已爬取集合
URL存儲方式:Python記憶體即set()集合,關係資料庫、緩存資料庫
(3)網頁下載器:根據URL獲取網頁內容,實現由有urllib2和request
(4)網頁解析器:從網頁中提取出有價值的數據,實現方法有:正則表達式、html.parser、BeautifulSoup、lxml等等
當然此處說的這麼多點我下麵的那個小爬蟲沒有涉及那麼多或者說是我的沒有大牛這麼規範,我剛開始的思路是這樣的:首先我想到要用正則表達式篩選我要的信息,所以剛開始肯定要調用模塊re,然後獲取網頁信息我們需要一個urllib模塊(我這裡寫的是一個python2的爬蟲,用的是urllib),然後我的主體模塊是函數式寫法(後面才慢慢來oop),首先我先寫一個網頁獲取函數,當然也需要先給一個網頁地址變數,
此處就是爬蟲的一部分,上面兩個是兩個模塊,下麵url變數是網頁地址變數,我是隨便打開的一個網頁取的地址,此處大家可以隨意發揮,然後下麵就是網頁獲取函數,這個函數有一個參數,就是url,網頁地址,然後第一句就是調用urllib的一個函數urlopen打開這個網頁並且存儲在變數page中,然後下麵就是一個文件讀取操作,page(相當於文件名).read(文件讀取函數,讀取文件中的數據).decode(讀取的格式轉換),此處是轉換成utf-8,至於utf-8格式,我還是百度一下翻譯內容吧
大致也就是轉換能夠適合人懂的格式吧,然後用這個文件操作獲取到整個網頁的信息了之後就把信息存儲到變數html中,最後將獲取到的信息返回出去。
到此處就相當於簡單粗略的將一個網頁的信息爬取出來了,這其實也可以算得上是一個爬蟲,最原始的爬蟲吧,就只有獲取整個網頁信息的能力,不細分不修改,功能就是獲取網頁,如果此處print到控制台的話就是一大串html代碼,如果沒接觸過html的,看到這樣的信息肯定是有點蒙的,那麼接下來我們就要進行下一個函數(對網頁信息進行分析並且用正則表達式篩選出我們需要的內容)
這個函數就是將獲取到的html源碼進行解析並且用正則表達式篩選出我們需要的,此處我們需要獲取整個網頁的圖片,那麼我們就先定義一個正則表達式,格式一般是變數名=r'正則表達式',此處我是需要取到圖片,所以我就先寫.gif(此處最開始我寫的是jpg,一直沒發現,後來試了好久,改了好久才發現是gif,簡直就很難受啊,哎,感覺如果學習的時候有個人在一旁指導那該是多麼幸福的事,不過感覺自學的感覺更爽,自己掉過的每一個坑都是自己人生當中的一大筆財富)至於為什麼是用gif格式呢,目前我也不太清楚,還是希望各位園裡大佬多多指教,小白洗耳恭聽,我們要匹配到尾碼都是gif的話那就是要用到\符號,這個符號我上一篇說到了,是將所有字元轉換為普通字元,然後搜索時就會按照.gif找,然後前面匹配名字的話我用的是.+?意思也就是匹配所有名字,意思就是匹配所有尾碼是.gif格式的文件,前面名稱可以隨意,但是最少要出現一次,此處也可以將+換成*,那樣就是名稱最少出現一次,前面src=就是html代碼中的地址聲明格式之類的,瞭解html的都清楚每個圖片標簽語句都要用src=圖片路徑來將圖片放置在網頁裡面,此處我們就將篩選條件寫好了,下麵我們就用re裡面的一個編譯函數編譯一下,re.compile()就是編譯這個正則表達式,意思就是將正則表達式編譯進代碼,到後面調用篩選時更快,然後就是findall()函數,貪婪搜索,用來在html代碼中搜索出所有符合我們定義條件的內容,到此我們就算是將整個網頁分析抓取篩選工作搞完了,簡單吧,我覺得剛開始可能有點難理解,但是仔細一想還是挺簡單的,主要是把這種流程想清楚,抓取到了我們想要的內容之後接下來我們就要將其保存起來,下麵就是用一個for迴圈將將我們篩選到的內容保存,此處我們又要用到一個urllib裡面的函數urlretrieve,這個函數就是將內容保存到本地,預設是保存到項目下,當然此處還是可以放到另外的部分,不過我沒有嘗試,最下麵還有兩個語句搞忘記說了
也就是用這個兩個函數,沒什麼說的,到此小爬蟲就完了,此處我用的是python2.7.
二:文件操作
文件操作這塊的話感覺有點像c語言的文件操作,但是感覺還是最開始那種思想,python寫法永遠比c語言簡單。
深拷貝和淺拷貝:此處兩個定義大致可以這麼理解,淺拷貝是對引用的拷貝,深拷貝是對對象資源的拷貝,淺拷貝是不完全獨立於之前的“父親”,深拷貝則是完全脫離,不管之後父文件有什麼改變,子文件都不會隨之改變,說到此處肯定有一些跟我一樣的小白不太懂,還是上代碼截圖比較明瞭,
大致就是上面這樣,小白弄得有點亂,不好意思各位了,這是淺拷貝,深拷貝就是父文件怎麼變,子文件都不會變。
接下來就是文件讀寫部分了:
文件打開函數就是open或者也可以用file類,一般來說我還是比較喜歡用open,此處也就只記錄open算了(深夜感覺想睡覺,哈哈,偷個懶),open(filename,mode),大致就是這兩個參數,第一個不用就是文件名,第二個就是打開模式,大致就是如下
這些大致就是mode的種類,當然此處說出來還是挺簡單的,還是要具體自己使用的時候慢慢體會其中的韻味,其中還有一些文件操作的函數我也就一一列舉出來
上面就是在找的比較全的文件操作的方法,當然如果要真正掌握這些還是要結合具體慢慢用,實踐才是唯一真理,我此處也是為了早點上床睡覺偷懶而為,希望各位不要噴我。我就舉個例子來簡單說下一些註意事項,open方法可以返回一個迭代數據,然後write和writelines在寫入前是否清除文件中的原來的數據,取決於模式,一般w模式就是清除原來的數據,還有seek(偏移量,選項)選項為0時,表示將指針指向從文件頭部到偏移量的位元組處,選項等於1時,表示將文件指針指向從文件當前位置,向後移動偏移量位元組,選項為2時,表示將文件指針指向從文件尾部,向前移動偏移量位元組。下麵舉一兩個小例子解釋一下文件操作吧。
第一個小例子是將文件一的數據“hello”拷貝到文件二中:
新建了兩個文本,一個1.txt,裡面有一些數據,其中有幾個hello,2.txt中有幾個lixun,我們就將一中的hello拷貝到2.txt文件中替換掉lixun,代碼如下
fp1 = file(“1.txt”,"r")
fp2 = file("2.txt","w")
for s in fp1.readlines():
fp2.write(s.replace("hello","lixun"))
fp1.close()
fp2.close()
至此就完成了操作,
我們將第一個例子升級一下,將1.txt中的hello換成lixun
fp1 = file(“1.txt”,“r+”)
s = fp1.read()
fp1.seek(0,0)
fp1.write(s.replace("lixun","hello"))
fp1.close
接下來就是socket編程了:
socket網路通信我也是在網上找的資料慢慢看,然後按照一些大佬寫的代碼參悟,
主要思想也是調用模塊(socket)然後就是分伺服器端程式跟客戶端程式,其實說起來高大上,真正搞懂了也就是一個通信模式,就跟單片機中的通信模塊一樣的,
客戶端模塊代碼就是import socket
s=socket.socket()
host=socket.gethostname()
port=1234
s.bind((host,port))
s.listen(5)
while True:
s,addr=s.accept()
print ("Got connect from %s:%s" % addr)
s.send("Thank you for connecting")
s.close()
伺服器端模塊:
import socket
s=socket.socket()
host=socket.gethostname()
port=1234
s.connect((host,port))
print s.recv(1024)
這大致就是一個簡單的socket通信編程,也就相當於兩台機器之間的通信,具體代碼也比較簡單,也就不細講了
接下來再放一個我理解了的socket的代碼吧
客戶端:
import socket
import sys
#創建socket函數
try:
s = socket.socket(socket.AF_INET,socket.sock_STREAM)
except socket.error,msg:
print 'Falied to create socket.Error code:'+str(msg[0])+',Error message:'+msg[1]
sys.exit();
print 'Socket Created'
#連接伺服器
host = 'www.google.com'
port = 80
try:
remote_ip = socket.gethostbyname(host)
except socket.gaierror:
print 'Hostname could not be resolved.Exiting'
sys.exit()
print 'Ip address of'+host+'is'+remote_ip
#連接到伺服器
s.connect((remote_ip,port))
print 'Socket Connected to'+host+'on ip'+remote_ip
#發送數據到伺服器
message = "GET / HTTP/1.1\r\n\r\n"
try:
s.sendall(message)
except socket.error:
print 'Send failed'
sys.exit()
print 'Message send successfully'
#接收數據
reply = s.recv(4096)
print reply
s.close()
伺服器端:
#綁定socket
import socket
import sys
from thread import *
HOST = ''
PORT = 8888
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
print 'Socket created'
try:
s.bind((HOST,PORT))
except socket.error,msg:
print 'Bind failed.Error Code:'+str(msg[0])+'Message'+msg[1]
sys.exit()
print 'Socket bind complete'
#監聽連接
s.listen(10)
print 'Socket now listening'
def clientthread(conn):
conn.send('Welcome to the sever.Type something and hit enter\n')
while True:
data= conn.recv(1024)
reply = 'OK...'+data
if not data:
break
conn.sendall(reply)
conn.close()
while 1:
conn,addr = s.accept()
print 'Connected with'+addr[0]+':'+str(addr[1])
start_new_thread(clientthread,(conn,))
s.close()
這裡面新知識可能就是那個線程問題,有過一些代碼基礎的同學應該對線程概念不陌生。這一塊我也只是瞭解了一下,因為下個月二十幾號就要用socket通信,所以也就沒時間深究其原理及其細節
下麵就是oop編程了
四:oop編程
oop編程是我要在choregraphe軟體裡面寫盒子要用到的部分,所以這部分我還是打算慢慢來搞,,感覺python的oop寫法還是跟c++和c#有所不同,至少c#裡面我還沒遇到過要用什麼self,可能我學
不深吧,有些奧義還沒有接觸到,各位大佬莫怪,當然,python的面向對象編程書寫起來還是挺方便的,
創建類就是class className():,這樣就創建了一個類,跟c#還是挺像的,
,然後裡面還可以加'class documentation string'#類文檔字元串,然後基本上類裡面都會有一個構造函數def _name_(self,canshu1,canshu2):這就大致是構造函數的寫法,函數名稱必須是
——_name_中間是名稱,開始和結尾都必須有_下劃線,括弧中的參數,最開始必須是self,至於為什麼,我目前尚未究其緣由,剛剛寫著的時候突然發現自己還是沒太明白其中奧義,所以感覺今天還是先別說,留著
下一篇理解摸清楚了再來細講吧。
我是小白隨風狼人小白,我為自己代言,哈哈,晚安,各位大牛