1. 程式人生 > >python爬蟲(1)——簡單的爬取網頁的資訊

python爬蟲(1)——簡單的爬取網頁的資訊

獲取網上真實的語料資料,本身對Py的掌握不是很好,記錄下自己學習的過程,希望對你有幫助。 #python3 獲得taoeba的語料(不知道從哪翻到的這個網站,有各國語言的句子,訪問速度較慢
# -*- coding: utf-8 -*-
import requests
from bs4 import BeautifulSoup as BS
import time
import re
python3中的urllib以及requestshttp://blog.csdn.net/drdairen/article/details/51149498
#對句子列表網頁進行獲取,得到一個list包含句子連結
def get_selist(url):
    try:
        response = requests.get(url, headers=headers) #訪問所有句子列表
        soup = BS(response.text, "lxml")  #解析網頁
        urls = soup.find_all(href=re.compile('.*/cmn/sentences/show/[0-9].*')) #找到所有我要的<a>標籤  得到一個list  接下來提取元素的href
        sentences = [] #存href
        for i in urls:  #遍歷<a>標籤列表
            sentences.append(i.get('href')) #get('href')只能對標籤字串操作,剛開始我直接對urls.get()是不可以的。。。
        sentences = list(set(sentences)) #對得到的href列表去重
        return sentences  #返回連結的list
    except Exception as e:  #網頁訪問錯誤就返回空列表
        a = []
        print('獲取句子列表失敗  連結為'+url)
        return a
headers = {'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36'}
url = 'https://tatoeba.org/cmn/sentences/show_all_in/cmn/none/none/indifferent/page:'      #分析發現所有中文句子的網頁規律
h = 'https://tatoeba.org'     #為了訪問詞的地址  地址一般為../cmn/sentences/show/[0-9]
header用來假裝自己是個瀏覽器,有時也會需要cookie等。
檢視你的瀏覽器的user-agent ——位址列中輸入:about:version   檢視user-agents 直接指令碼訪問,可能會出現這樣的報錯: ... ... urllib.error.HTTPError: HTTP Error 403: Forbidden
#對句子列表網頁進行獲取,得到一個list包含句子連結
def get_selist(url):
    try:
        response = requests.get(url, headers=headers) #訪問所有句子列表
        soup = BS(response.text, "lxml")  #解析網頁
        urls = soup.find_all(href=re.compile('.*/cmn/sentences/show/[0-9].*')) #找到所有我要的<a>標籤  得到一個list  接下來提取元素的href
        sentences = [] #存href
        for i in urls:  #遍歷<a>標籤列表
            sentences.append(i.get('href')) #get('href')只能對標籤字串操作,剛開始我直接對urls.get()是不可以的。。。
        sentences = list(set(sentences)) #對得到的href列表去重
        return sentences  #返回連結的list
    except Exception as e:  #網頁訪問錯誤就返回空列表
        a = []
        print('獲取句子列表失敗  連結為'+url)
        return a
# 解析一個詞的網頁  返回fr/es的兩個列表[zh:fr,zh:fr],[zh:sp,zh:sp]
def getext(url1):
    def text(tag):#內建函式,傳入一個標籤列表,獲得每一個text資訊,返回一個list
        a = []
        for i in tag:
            a.append(i.get_text())
        return a
    try:
        response = requests.get(url1, headers=headers)#同上
        soup = BS(response.text, "lxml")
        zh = text(soup.find_all('div', attrs={'lang': 'zh-Hans'})) #獲得對應屬性的標籤  這個找的是含有中文的標籤
        fr = text(soup.find_all('div', attrs={'lang': 'fr'}))#法語
        sp = text(soup.find_all('div', attrs={'lang': 'es'}))  #西班牙語
        zh2fr = [] 
        zh2sp = []  #兩個list存對應語料資訊
        for f in fr:   #將對應語料格式化
            zh2fr.append(zh[0] + '||||' + f)
        for s in sp:
            zh2sp.append(zh[0] + '||||' + s)
        print(zh2fr, zh2sp)
        return zh2fr, zh2sp #返回兩個列表,方便寫入兩個檔案
    except Exception as e:  #同樣錯誤則返回空
        a = []
        b = []
        print('獲取句子失敗  連結為'+url1)
        return a,b
#因為得到的是對應語料的list  構造一個函式  方便寫入檔案
def _write(file,fr):
    if len(fr):
        for i in fr:
            file.write(i+'\n')

#開始的操作~
zh2fr = open('zh2fr','a',encoding='utf-8')  #將要寫入的兩個檔案
zh2sp = open('zh2sp','a',encoding='utf-8')
url_list = []

#獲得所有句子的連結,應該是有5094頁,取了一頁測試
for i in range(1,2):
    url_list.extend(get_selist(url+str(i))) #將列表連在一起

begin = time.time() #時間記錄

#訪問所有的句子連結,獲得平行語料並寫入檔案
for j in url_list:
    (fr,sp) = getext(h+j)
    _write(zh2fr,fr)
    _write(zh2sp,sp)
end = time.time()

print('use time %s'%(end-begin))

#對了,不要忘了close開啟的檔案
zh2ru.close()
zh2fr.close()
這個指令碼的效率不是很高,首先因為網站訪問很慢,時間不一定(一套下來10多秒也有可能,幾百秒也有可能。。)
# 主要加了sleep random  避免訪問過快
# 解析一個詞的網頁  返回fr/es的兩個列表[zh:fr,zh:fr]
#多加了一門語言
def getext(url1):                                                                                                     
    def text(tag):                                                            
        a = []
        for i in tag:
            a.append(i.get_text())
        return a
    try:
        time.sleep(random.randint(0,5))   #避免句子同時訪問太快。。沒有對執行緒任務的時間控制,感覺這麼寫比較簡單。。                                                     
        response = requests.get(url1, headers=headers)
        soup = BS(response.text, "lxml")
        zh = text(soup.find_all('div', attrs={'lang': 'zh-Hans'}))
        fr = text(soup.find_all('div', attrs={'lang': 'fr'}))
        sp = text(soup.find_all('div', attrs={'lang': 'es'}))
        ru = text(soup.find_all('div', attrs={'lang': 'ru'}))
        zh2fr = []
        zh2sp = []
        zh2ru = []
        for f in fr:
            zh2fr.append(zh[0] + '||||' + f)
        for s in sp:
            zh2sp.append(zh[0] + '||||' + s)
        for r in ru:
            zh2ru.append(zh[0] + '||||' + r)
        print(zh2fr, zh2sp, zh2ru)
        return zh2fr, zh2sp, zh2ru
    except Exception as e:
        a = []
        print('獲取句子失敗  連結為'+url1)
        return a,a,a

# 主要加了這個函式  獲得句子連結沒有用多執行緒,訪問句子網頁用的,因為訪問太快會報錯。。雖然不會被封,但是無法獲得資訊了
#訪問一頁,就獲取所有的句子,避免了過快訪問
def get_url(i):
    url_list = (get_selist(url + str(i)))                                                                             #獲得句子的網址列表,用的寫好的函式。
    print('page'+str(i)+'ok---'+str(len(url_list)))
    def fetch_content(url):                                                                                            #任務函式
        (fr, sp, ru) = getext(h + url)
        _write(zh2fr, fr)
        _write(zh2sp, sp)
        _write(zh2ru, ru)
    threads2 = []                                                                                                            #多執行緒任務的封裝
    for j in url_list:
        t = Thread(target=fetch_content, args=[j])
        t.start()
        threads2.append(t)
    for t in threads2:
        t.join()

這樣比單執行緒快了許多,爬取網頁資訊還是不要訪問太快了。。對網站的伺服器友好一點。。
下一步將要學習一下動態網頁資訊的爬取,通過scrapy 深入瞭解一下執行緒程序,以及網路爬蟲機制(作業系統?網路?)
發現什麼問題,或者有什麼建議請告訴我~謝謝~