1. 程式人生 > >python-對貓眼網的top100的爬取

python-對貓眼網的top100的爬取

python我從今年過年開始自學,斷斷續續的,最近參加了一個爬蟲訓練營,我發現爬蟲對開始學習python是非常合適的,只不過首先得具備一些HTML的知識儲備,畢竟爬蟲是需要解析網頁的。而且爬蟲實現後的成就感是非常巨大的。所以,根據上週學習的一些知識,做一個小的總結。

首先需要安裝requests庫和beautifulsoup庫,這兩個庫是有函式可以對網頁進行一個解析操作的。比如request中的get()。beautifulsoup中的Beautifulsoup()的使用。

安裝過程

首先最簡單的安裝就是利用cmd通過pip指令安裝

pip install requests
pip install beautifulsoup4 //
這裡需要注意一下,後面必須有個4

如果安裝不上,那就從網上先下載好需要的安裝檔案,在進入該檔案的目錄下,進行安裝。

request的使用

request的請求方式有多種,因為是一個第三方庫,有多種使用方法,可以在網上尋找一些使用文件參考

requests.get('http://www.xxxxxxxx.com')
requests.post('http://www.xxxxxxxx.com')
requests.delete('http://www.xxxxxxxx.com')
requests.put('http://www.xxxxxxxx.com')
requests.head('http://www.xxxxxxxx.com'
)

列舉一些常用的。

get:請求指定的頁面資訊,並返回一個主體。使用get方式時,請求資料直接放在url中。

post:請求主要是傳送一些較長的資料,資料比較安全 。使用post方式時,資料放在data或者body中,不能放在url中,放在url中將被忽略。

delete:請求伺服器刪除Request-URI所標識的資源。

put:向指定資源位置上傳其最新內容 。

head: 向伺服器索要與GET請求相一致的響應,只不過響應體將不會被返回。這一方法可以在不必傳輸整個響應內容的情況下,就可以獲取包含在響應訊息頭中的元資訊。

request的例項

首先我們要爬取的是貓眼網站的top100榜單。網址為http://maoyan.com/board/4。

111

這是第一頁的情況,此時我們點選一個下一頁,就能發現網址發現了變化。

222

能明顯看到網址的變化是http://maoyan.com/board/4?offset={}。

不斷去往下翻頁,我們就能看到offset=後面這個數在不斷的變化,第一頁是0,到最後一頁是90。

說明offset是偏移量,等於號後面的是偏移量的值

知道了這個url的規律之後,就可以來進行獲取網址了。

通過get去獲取一個網頁資訊

def get_url(url):
    try:
        wb_data=requests.get(url)
        wb_data.raise_for_status
        wb_data.encoding=wb_data.apparent_encoding
        return wb_data.text
    except:
        return "程式碼段異常"

上面是單個網頁去抓取。我們能發現,此時所有的html頁面資訊都被反饋出來了。

我們利用谷歌瀏覽器開啟該網站,右鍵點選檢查,我們能看到各個標籤內的字串在其中,這個時候我們就需要正則表示式將其提取出來。

def parse_one_page(html):
    pattern=re.compile('<dd>.*?board-index.*?>(.*?)</i>.*?data-src="(.*?)".*?name.*?a.*?>(.*?)</a>.*?star.*?>(.*?)</p>.*?releasetime.*?>(.*?)</p>.*?integer.*?>(.*?)</i>.*?fraction.*?>(.*?)</i>.*?</dd>',re.S)
    items=re.findall(pattern,html)
    for item in items:         
        yield{             
                'index':item[0],
                'img':item[1],
                '名稱':item[2],
                '主演':item[3].strip()[3:],
                '上映時間':item[4].strip()[5:]
                }

關於正則表示式不在這裡詳細說了,以後我會專門寫一篇總結。

yield的用法:如果一個函式包含yield關鍵字,這個函式就會變為一個生成器。

生成器並不會一次返回所有結果,而是每次遇到yield關鍵字後返回相應結果,並保留函式當前的執行狀態,等待下一次的呼叫。所以在我們去請求網頁的過程中,每尋找一次,找到相對應的標籤,就將其內容爬取下來。

接下來需要對offset這個偏移量找到方法將他新增到我們的url中,並且可以迴圈的使用。

def main(offset):
    url='http://maoyan.com/board/4?offset={0}'.format(offset)
    html=get_url(url)
    for item in get_url(html):
        print(item)

format函式就不需要多說了,就是往其中新增字串。這裡利用一個for迴圈使用,這樣可以迴圈將網頁都在函式get_url中請求一次。

最後將它輸出出來

for i in range(10):
    main(offset=i*10)
    time.sleep(2)

在控制檯觀察,就會發現我們需要的網頁資訊被一個一個的提取出來了。

這裡使用了一個time.sleep(2),它的作用是讓請求有一定的間隔,我們都知道各個網站具有反爬蟲機制,如果訪問太頻繁,則會被禁止訪問。讓2s訪問一次,則可以避免這種機制。

這就是一個簡單的爬取過程。接下來是更具體的一種。利用了beautifulsoup來使用

BeautifulSoup的用法

‘美味湯’,是用Python寫的一個HTML/XML的解析器,它可以很好的處理不規範標記並生成剖析樹(parse tree)。 它提供簡單又常用的導航(navigating),搜尋以及修改剖析樹的操作。它可以大大節省你的程式設計時間。

//引用該庫的方法不是直接import就可以,而是通過from
form bs4 import beautifulsoup

soup=BeautifulSoup(wb_data.text,'lxml')

print(soup.find_all('a')print(soup.get_text()//以上是舉例它的寫法

soup 就是BeautifulSoup處理格式化後的字串,soup.title 得到的是title標籤,soup.p 得到的是文件中的第一個p標籤,要想得到所有標籤,得用find_all

函式。find_all 函式返回的是一個序列,可以對它進行迴圈,依次得到想到的東西.

get_text() 是返回文字,這個對每一個BeautifulSoup處理後的物件得到的標籤都是生效的。

我們在上面看到一個‘lxml’這個東西,這是解析庫。在這裡說明一下

解析器 使用方法 優勢 劣勢
python標準庫 BeautifulSoup(markup,‘parser’) python內建;執行速度適中;文件容錯能力強 低版本pyton容錯能力差
lxml HTML解析器 BeautifulSoup(markup,‘lxml’) 速度快;容錯能力強 需要安裝lxml
lxml XML解析器 BeautifulSoup(markup,‘xml’) 速度快;唯一支援XML 需要安裝lxml
Html5lib BeautifulSoup(markup,‘html5lib’) 容錯性最好 速度慢;需要安裝html5lib

在我們知道解析器之後,我們還要做的就是通過什麼去選擇標籤。這裡一般有四種常用選擇器

選擇器 作用 使用方法
節點選擇器 通過節點名稱巢狀選取資訊 soup.div.next_sibling.ul.li.p
方法選擇器 find_all()和find()函式 soup.find(name=‘p’,class=’ ')
css選擇器 Select方法 body>div.content>ul>li:nth-child(1)>p
Xpath 用於在xml文件中搜索元素的路徑語言 /html/body/div[2]/ul/li[1]/p

當我們基本瞭解之後就可以使用了。

在下面的使用中,就利用select方法

333

我們能看到黃色的地方就是我們需要的title標籤所指向的地方。

右擊這個標籤,點選copy---->copy selector就是利用css選擇器,這之後複製出來的標籤走向最後複製到select()方法中。

def parse_one_page(html):
    soup=BeautifulSoup(''.join(html),'lxml')
#在這裡我們是得到了R.txt的文字,但是我們不能輸出,所以我們得利用print來輸出
    titles=soup.select('#app > div > div > div.main > dl > dd > div > div > div.movie-item-info > p.name > a')
    pics=soup.select('#app > div > div > div.main > dl > dd > a > img.board-img')
    actors=soup.select('#app > div > div > div.main > dl > dd > div > div > div.movie-item-info > p.star')
    days=soup.select('#app > div > div > div.main > dl > dd > div > div > div.movie-item-info > p.releasetime')
    scores1=soup.select('#app > div > div > div.main > dl > dd > div > div > div.movie-item-number.score-num > p > i.integer')
    scores2=soup.select('#app > div > div > div.main > dl > dd > div > div > div.movie-item-number.score-num > p > i.fraction')
    for title,pic,actor,day,scores,scoress in zip(titles,pics,actors,days,scores1,scores2):
        info={
                'title':title.get_text(),
                'pic':pic.get('alt'),
                'actor':actor.get_text(),
                'day':day.get_text(),
                'scores':scores.get_text()+scoress.get_text(),
                }
        write_to_file(info)
        print(info)

在上面有一個自己定義的wirte_to_file()函式。爬取完資料後,一直放在控制檯顯示只能證明我們爬取成功了。所以定義函式將我們所請求到的資料放入一個檔案中,可以供我們需要的時候看看。

def write_to_file(content):
    with open('maoyan.text','a',encoding='utf-8') as f:
        f.write(json.dumps(content,ensure_ascii=False)+'\n')

with open()這個函式的使用時,有四種文字可以儲存,分別是text,json,csv,excel。後兩種還可以利用pandas來處理統計。

完整程式碼

import json
import requests
import time
from bs4 import BeautifulSoup

def get_one_page(url):
    headers={'user-agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.104 Safari/537.36 Core/1.53.2263.400 QQBrowser/9.5.10429.400'}
    response=requests.get(url,headers=headers)
    if response.status_code==200:
        return response.text
    else:
        return None
data=[]
def parse_one_page(html):
    soup=BeautifulSoup(''.join(html),'lxml')
#在這裡我們是得到了R.txt的文字,但是我們不能輸出,所以我們得利用print來輸出
    titles=soup.select('#app > div > div > div.main > dl > dd > div > div > div.movie-item-info > p.name > a')
    pics=soup.select('#app > div > div > div.main > dl > dd > a > img.board-img')
    actors=soup.select('#app > div > div > div.main > dl > dd > div > div > div.movie-item-info > p.star')
    days=soup.select('#app > div > div > div.main > dl > dd > div > div > div.movie-item-info > p.releasetime')
    scores1=soup.select('#app > div > div > div.main > dl > dd > div > div > div.movie-item-number.score-num > p > i.integer')
    scores2=soup.select('#app > div > div > div.main > dl > dd > div > div > div.movie-item-number.score-num > p > i.fraction')
    for title,pic,actor,day,scores,scoress in zip(titles,pics,actors,days,scores1,scores2):
        info={
                'title':title.get_text(),
                'pic':pic.get('alt'),
                'actor':actor.get_text(),
                'day':day.get_text(),
                'scores':scores.get_text()+scoress.get_text(),
                }
        write_to_file(info)
        print(info)

def write_to_file(content):
    with open('maoyan.excel','a',encoding='utf-8') as f:
        f.write(json.dumps(content,ensure_ascii=False)+'\n')

def main(offset):
    url='https://maoyan.com/board/4?offset='+str(offset)
    html=get_one_page(url)
    parse_one_page(html)

for i in range(10):
    main(offset=i*10)
    time.sleep(1)

以上就是我們的爬取過程,並不算複雜,而且是比較容易爬取的!可以讓你瞬間有成就感的那種!

爬取出來的是放在字典內的,一條一條在文字檔案中,觀看是非常醒目的。動手試試吧!