久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

Python抓取網(wǎng)頁&批量下載文件方法初探(正則表達(dá)式+BeautifulSoup)

 當(dāng)年剩女圖書館 2013-09-29

Python抓取網(wǎng)頁&批量下載文件方法初探(正則表達(dá)式+BeautifulSoup)

分類: ubuntu python 數(shù)據(jù)挖掘 655人閱讀 評論(0) 收藏 舉報

最近兩周都在學(xué)習(xí)Python抓取網(wǎng)頁方法,任務(wù)是批量下載網(wǎng)站上的文件。對于一個剛剛?cè)腴Tpython的人來說,在很多細(xì)節(jié)上都有需要注意的地方,,以下就分享一下我在初學(xué)python過程中遇到的問題及解決方法。


一,、用Python抓取網(wǎng)頁

基本方法:

  1. <span style="font-size:14px;">import urllib2,urllib  
  2.   
  3. url = 'http://www.baidu.com'  
  4. req = urllib2.Request(url)  
  5. content = urllib2.urlopen(req).read()</span>  

1)、url為網(wǎng)址,需要加'http://'

2),、content為網(wǎng)頁的html源碼


問題:

1,、網(wǎng)站禁止爬蟲,不能抓取或者抓取一定數(shù)量后封ip

解決:偽裝成瀏覽器進(jìn)行抓取,,加入headers:

  1. <span style="font-size:14px;">import urllib2,urllib  
  2.   
  3. headers = { #偽裝為瀏覽器抓取  
  4.         'User-Agent':'Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6'  
  5.     }  
  6.   
  7. req = urllib2.Request(url,headers=headers)  
  8. content = urllib2.urlopen(req).read()</span>  
  1. <span style="font-size:14px;">  
  2. </span>  
更復(fù)雜的情況(需要登錄,,多線程抓取)可參考:http://www./python-network-application/observer-spider,,很不錯的教程


2,、抓取網(wǎng)頁中的中文為亂碼問題

解決:用BeautifulSoup解析網(wǎng)頁(BeautifulSoup是Python的一個用于解析網(wǎng)頁的插件,其安裝及使用方法下文會單獨(dú)討論)

首先需要介紹一下網(wǎng)頁中的中文編碼方式,,一般網(wǎng)頁的編碼會在<meta>標(biāo)簽中標(biāo)出,,目前有三種,分別是GB2312,,GBK,,GB18030,三種編碼是兼容的,,

從包含的中文字符個數(shù)比較:GB2312 < GBK < GB18030,,因此如果網(wǎng)頁標(biāo)稱的編碼為GB2312,但是實(shí)際上用到了GBK或者GB18030的中文字符,,那么編碼工具就會解析錯誤,,導(dǎo)致編碼退回到最基本的windows-2152了。所以解決此類問題分兩種情況,。

1),、若網(wǎng)頁的實(shí)際的中文編碼和其標(biāo)出的相符的話,即沒有字符超出所標(biāo)稱的編碼,,下面即可解決

  1. <span style="font-size:14px;">import urllib,urllib2,bs4  
  2.       
  3. req = urllib2.Request(url)  
  4. content = urllib2.urlopen(req).read()  
  5. content = bs4.BeautifulSoup(content)  
  6. return content</span>  

2),、若網(wǎng)頁中的中文字符超出所標(biāo)稱的編碼時,需要在BeautifulSoup中傳遞參數(shù)from_encoding,,設(shè)置為最大的編碼字符集GB18030即可

  1. <span style="font-size:14px;">import urllib,urllib2,bs4  
  2.       
  3. req = urllib2.Request(url)  
  4. content = urllib2.urlopen(req).read()  
  5. content = bs4.BeautifulSoup(content,from_encoding='GB18030')  
  6. return content</span>  


詳細(xì)的中文亂碼問題分析參見:http://againinput4.blog.163.com/blog/static/1727994912011111011432810/

二,、用Python下載文件

使用Python下載文件的方法有很多,在此只介紹最簡單的一種

  1. <span style="font-size:14px;">import urllib  
  2.   
  3. urllib.urlretrieve(url, filepath)</span>  

url為下載鏈接,,filepath即為存放的文件路徑+文件名


更多Python下載文件方法參見:http:///code-snippet/83/sanzhong-Python-xiazai-url-save-file-code


三,、使用正則表達(dá)式分析網(wǎng)頁

將網(wǎng)頁源碼抓取下來后,就需要分析網(wǎng)頁,,過濾出要用到的字段信息,,通常的方法是用正則表達(dá)式分析網(wǎng)頁,一個例子如下:

  1. <span style="font-size:14px;">import re  
  2.   
  3. content = '<a   
  4. match = re.compile(r'(?<=href=["]).*?(?=["])')  
  5. rawlv2 = re.findall(match,content)</span>  

用re.compile()編寫匹配模板,,用findall查找,,查找content中所有與模式match相匹配的結(jié)果,,返回一個列表,上式的正則表達(dá)式意思為匹配以‘href="'起始,,以'"'結(jié)束的字段,,使用非貪婪的規(guī)則,只取中間的部分

關(guān)于正則表達(dá)式,,系統(tǒng)的學(xué)習(xí)請參見:http://www.cnblogs.com/huxi/archive/2010/07/04/1771073.html

或 http://wiki./Python%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E5%BC%8F%E6%93%8D%E4%BD%9C%E6%8C%87%E5%8D%97

個人推薦第一篇,,條理清晰,不重不漏

在此就不贅述正則表達(dá)式的學(xué)習(xí),,只總結(jié)一下我在實(shí)際寫正則時的認(rèn)為需要注意的幾個問題:

1),、一定要使用非貪婪模式進(jìn)行匹配,即*?,+?(后加?),,因為Python默認(rèn)使用貪婪模式進(jìn)行匹配,,例如'a.*b',它會匹配文檔中從第一個a和最后一個b之間的文本,,也就是說如果遇到一個b,,它不會停止,會一直搜索至文檔末尾,,直到它確認(rèn)找到的b是最后一個,。而一般我們只想取某個字段的值,貪婪模式既不能返回正確的結(jié)果,,還大大浪費(fèi)了時間,,所以非貪婪是必不可少的

2)、raw字符串的使用:如果要匹配一個.,*這種元字符,,就需要加'\'進(jìn)行轉(zhuǎn)義,,即要表示一個'\',正則表達(dá)式需要多加一個轉(zhuǎn)義,,寫成'\\',,但是Python字符串又需要對其轉(zhuǎn)義,最終變成re.compile('\\\\'),,這樣就不易理解且很亂,,使用raw字符串讓正則表達(dá)式變得易讀,即寫成re.compile(r'\\'),,另一個方法就是將字符放到字符集中,,即[\],效果相同

3),、()特殊構(gòu)造的使用:一般來說,,()中的匹配模式作為分組并可以通過標(biāo)號訪問,但是有一些特殊構(gòu)造為例外,,它們適用的情況是:我想要匹配href="xxxx"這個模式,,但是我只需要xxxx的內(nèi)容,,而不需要前后匹配的模式,這時就可以用特殊構(gòu)造(?<=),,和(?=)來匹配前后文,,匹配后不返回()中的內(nèi)容,剛才的例子便用到了這兩個構(gòu)造,。

4)、邏輯符的使用:如果想匹配多個模式,,使用'|'來實(shí)現(xiàn),,比如

  1. <span style="font-size:14px;">re.compile(r'.htm|.mid$')</span>  


匹配的就是以.htm或.mid結(jié)尾的模式,注意沒有'&'邏輯運(yùn)算符


四,、使用BeautifulSoup分析網(wǎng)頁

BeautifulSoup是Python的一個插件,,用于解析HTML和XML,是替代正則表達(dá)式的利器,,下文講解BS4的安裝過程和使用方法

1,、安裝BS4

下載地址:http://www./software/BeautifulSoup/#Download

下載 beautifulsoup4-4.1.3.tar.gz,解壓:linux下 tar xvf beautifulsoup4-4.1.3.tar.gz,,win7下直接解壓即可

linux:

進(jìn)入目錄執(zhí)行:

 1, python setup.py build 

 2, python setup.py install 

或者easy_install BeautifulSoup

win7:

cmd到控制臺 -> 到安裝目錄 -> 執(zhí)行上面兩個語句即可


2,、使用BeautifulSoup解析網(wǎng)頁

本文只介紹一些常用功能,詳細(xì)教程參見BeautifulSoup中文文檔:http://www./software/BeautifulSoup/bs3/documentation.zh.html

1),、包含包:import bs4

2),、讀入:

  1. <span style="font-size:14px;">req = urllib2.Request(url)  
  2. content = urllib2.urlopen(req).read()  
  3. content = bs4.BeautifulSoup(content,from_encoding='GB18030')  
  4. </span>  

3)、查找內(nèi)容

a,、按html標(biāo)簽名查找:

  1. <span style="font-size:14px;">frameurl = content.findAll('frame')</span>  

framurl為存儲所有frame標(biāo)簽內(nèi)容的列表,,例如frame[0] 為 <framename="m_rtop" target="m_rbottom"src="tops.htm">

b、按標(biāo)簽屬性查找

  1. <span style="font-size:14px;">frameurl = content.findAll(target=True)</span>  

查找所有含target屬性的標(biāo)簽

  1. <span style="font-size:14px;">frameurl = content.findAll(target=‘m_rbottom’)</span>  

查找所有含target屬性且值為'm_rbottom'的標(biāo)簽

c,、帶有正則表達(dá)式的查找

  1. <span style="font-size:14px;">rawlv2 = content.findAll(href=re.compile(r'.htm$'))</span>  

查找所有含href屬性且值為以'.htm'結(jié)尾的標(biāo)簽

d,、綜合查找

  1. <span style="font-size:14px;">frameurl = content.findAll('frame',target=‘rtop’)</span>  

查找所有frame標(biāo)簽,且target屬性值為'rtop'


4),、訪問標(biāo)簽屬性值和內(nèi)容

a,、訪問標(biāo)簽屬性值

  1. <span style="font-size:14px;">rawlv2 = content.findAll(href=re.compile(r'.htm$'))  
  2. href = rawlv2[i]['href']</span>  


通過[屬性名]即可訪問屬性值,如上式返回的便是href屬性的值


b),、訪問標(biāo)簽內(nèi)容

  1. <span style="font-size:14px;">rawlv3 = content.findAll(href=re.compile(r'.mid$'))  
  2. songname = str(rawlv3[i].text)</span>  

上式訪問了<a href=...>(內(nèi)容)</a>標(biāo)簽的實(shí)際內(nèi)容,,由于text為unicode類型,所以需要用str()做轉(zhuǎn)換


附上最終的成果,,程序功能是抓取www.上的所有midi文件并下載,,需要先建立./midi/dugukeji/文件夾和./midi/linklist文件

  1. <span style="font-size:14px;">#-*- coding:utf-8 -*- #允許文檔中有中文  
  2. import urllib2,urllib,cookielib,threading  
  3. import os  
  4. import re  
  5. import bs4  
  6. import sys  
  7. reload(sys)  
  8. sys.setdefaultencoding('utf-8'#允許打印unicode字符  
  9.   
  10.   
  11. indexurl = 'http://www./'  
  12. databasepath = './midi/linklist'  
  13. path = './midi/dugukeji/'  
  14. totalresult = {}  
  15. oriresult = {}  
  16.   
  17. def crawl(url):  
  18.     headers = { #偽裝為瀏覽器抓取  
  19.         'User-Agent':'Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6'  
  20.     }  
  21.     req = urllib2.Request(url,headers=headers)  
  22.     content = urllib2.urlopen(req).read()  
  23.     content = bs4.BeautifulSoup(content,from_encoding='GB18030')  
  24.     return content  
  25.   
  26.   
  27. def crawlframe(sourceurl,target):  
  28.     global indexurl  
  29.     content = crawl(sourceurl)  
  30.     #match = re.compile(r'(?<=target=["]'+target+'["] src=["]).*?(?=["])')   #正則表達(dá)式方法  
  31.     #frameurl = re.findall(match,content)  
  32.     frameurl = content.findAll('frame',target=target)   #beautifulsoup方法  
  33.     result = indexurl+frameurl[0]['src']  
  34.     return result  
  35.   
  36. def crawllv1(frameurl,st=-1,en=-1):  
  37.     global indexurl  
  38.     content = crawl(frameurl)  
  39.     #match = re.compile(r'(?<=href=["]).*?(?=["])')  
  40.     #rawlv2 = re.findall(match,content)  
  41.     rawlv2 = content.findAll(href=re.compile(r'.htm$'))  
  42.     result = []  
  43.     if st==-1 and en==-1:  
  44.         for i in range(len(rawlv2)):  
  45.             result.append(indexurl+rawlv2[i]['href'])  
  46.     else:  
  47.         for i in range(st,en):  
  48.             result.append(indexurl+rawlv2[i]['href'])  
  49.     #dele = []  
  50.     #for i in range(len(result)):  
  51.     #   if result[i][-4:]!='.htm' and result[i][-5:]!='.html':  
  52.     #       dele.append(i)  
  53. #       else:  
  54. #           result[i]=indexurl+result[i]  
  55. #   if len(dele)>0:  
  56. #       for deli in dele:  
  57. #           del result[deli]  
  58.   
  59.     #result.sort()  
  60.     return result  
  61.   
  62. def crawllv2(lv2url):  
  63.     global indexurl  
  64.     content = crawl(lv2url)  
  65.     #match = re.compile(r'(?<=href=["]\.\.\/).*?[">].*?(?=[<])')  
  66.     #rawlv3 = re.findall(match,content)  
  67.     rawlv3 = content.findAll(href=re.compile(r'[..].*?[0-9].htm|.mid$'))  
  68.     #print rawlv3  
  69.     result = {} #結(jié)果字典,key:鏈接,,value:歌曲名  
  70.     for i in range(len(rawlv3)):  
  71.         tmp = str(rawlv3[i]['href'])  
  72.         #print tmp  
  73.         link = indexurl + tmp[tmp.rfind('..')+3:]   #有多個'..',,找到最后一個  
  74.         songname = ''  
  75.         if tmp[-4:]=='.htm':    #需要訪問3級頁  
  76.             try:  
  77.                 conlv3 = crawl(link)  
  78.             except:  
  79.                 print 'WARNING: visit lv3 url failed!\n'  
  80.             else:  
  81.                 rawlv4 = conlv3.findAll(href=re.compile(r'.mid$'))  
  82.                 if not rawlv4:  #4級頁沒有.mid下載鏈接,,略過  
  83.                     continue  
  84.                 else:  
  85.                     tmp = str(rawlv4[0]['href'])  
  86.                     link = indexurl + tmp[tmp.rfind('..')+3:]  
  87.   
  88.         songname = str(rawlv3[i].text)  #將unicode類型的text轉(zhuǎn)化為string  
  89.         #songname.decode('GBK')  
  90.         #songname.encode('utf-8')  
  91.         songname = songname.replace(' ','_')    #將songname中空格和換行轉(zhuǎn)化為下劃線  
  92.         songname = songname.replace('\n','_')   #原來存在的鏈接,直接略過  
  93.         if oriresult.has_key(link):  
  94.             continue  
  95.         if totalresult.has_key(link) and len(songname)<len(totalresult[link]):   #如果鏈接已保存且歌曲名長度比當(dāng)前的長,,略過  
  96.             continue  
  97.         else:  
  98.             totalresult[link] = songname  
  99.             result[link] = songname     #加入字典  
  100.     #result.sort()  
  101.     return result  
  102.   
  103. def download(totalresult):  
  104.     for link in totalresult.keys():  
  105.         filepath = path + totalresult[link] + '.mid'  
  106.         print 'download: ',link,' -> ',filepath,'\n'  
  107.         urllib.urlretrieve(link, filepath)  
  108.   
  109.   
  110. def readdata(databasepath):  
  111.     datafile = open(databasepath,'r')   #讀數(shù)據(jù)文件  
  112.     link = datafile.readline()  
  113.     while link:  
  114.         oriresult[link]=''  
  115.         link = datafile.readline()  
  116.     datafile.close()  
  117.   
  118. def writedata(databasepath):  
  119.     datafile = open(databasepath,'a')   #追加打開數(shù)據(jù)文件,,將新鏈接寫入文件尾  
  120.     for link in totalresult.keys():  
  121.         datafile.write(link,'\n')  
  122.     datafile.close()  
  123.   
  124. if __name__ == '__main__':  
  125.     try:  
  126.         readdata(databasepath)  #訪問文件,記錄已下載的鏈接  
  127.     except:  
  128.         print 'WARNING:read database file failed!\n'  
  129.     else:  
  130.         print 'There is ',len(oriresult),' links in database.\n'  
  131.   
  132.     try:  
  133.         frameurl1 = crawlframe(indexurl,'rtop'#抓取主頁中一級頁url所在frame的url  
  134.     except:  
  135.         print 'WARNING: crawl lv1 frameurl failed!\n'  
  136.     try:  
  137.         urllv1 = crawllv1(frameurl1,4,20)       #抓取一級頁url  
  138.     except:  
  139.         print 'WARNING: crawl lv1 url failed!\n'  
  140.   
  141.     for i in urllv1:  
  142.         print 'lv1 url:',i  
  143.         try:  
  144.             frameurl2 = crawlframe(i,'rbottom'#抓取一級頁中二級頁url所在frame的url  
  145.         except:  
  146.             print 'WARNING: crawl lv2 frameurl failed!\n'  
  147.         else:  
  148.             print '\tlv2 frameurl:',frameurl2  
  149.             try:  
  150.                 urllv2 = crawllv1(frameurl2)    #抓取二級頁url  
  151.             except:  
  152.                 print 'WARNING: crawl lv2 url failed!\n'  
  153.             else:  
  154.                 for j in urllv2:  
  155.                     print '\t\tlv2 url:',j  
  156.                     try:  
  157.                         urllv3 = crawllv2(j)  
  158.                     except:  
  159.                         print 'WARNING: crawl lv3 url failed!\n'  
  160.                     else:  
  161.                         for k in urllv3.keys():  
  162.                             print '\t\t\tlv3 url:',k,'\tname:',urllv3[k]  
  163.                         #download(urllv3)  
  164.                               
  165.     print 'new added midi num:',len(totalresult)  
  166.     print '\nbegin to download...\n'  
  167.     download(totalresult)  
  168.     print '\nWrite database...\n'  
  169.     writedata(databasepath)  
  170.     print '\n\nDone!\n'  
  171.   
  172.   
  173.   
  174.   
  175. """ 
  176. url = 'http://www./' 
  177. req = urllib2.Request(url) 
  178. response = urllib2.urlopen(req).read() 
  179. response = unicode(response,'GBK').encode('UTF-8') 
  180. print response 
  181. """</span>  


    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,,所有內(nèi)容均由用戶發(fā)布,,不代表本站觀點(diǎn)。請注意甄別內(nèi)容中的聯(lián)系方式,、誘導(dǎo)購買等信息,,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,,請點(diǎn)擊一鍵舉報,。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多