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。
這是第一頁的情況,此時我們點選一個下一頁,就能發現網址發現了變化。
能明顯看到網址的變化是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方法
我們能看到黃色的地方就是我們需要的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)
以上就是我們的爬取過程,並不算複雜,而且是比較容易爬取的!可以讓你瞬間有成就感的那種!
爬取出來的是放在字典內的,一條一條在文字檔案中,觀看是非常醒目的。動手試試吧!