#目標: 提取出貓眼電影TOP100的電影名稱、時間、評分、圖片等信息
#提取站點 :http://maoyan.com/board/4 提取的結果以文件形式保存
#使用知識: 網頁基礎 、網絡基礎 、urllib、requests、正則表達式
1.抓取分析:
1.網站頁面 有效信息:影片名稱 主演 上映時間 上映地區 評分 圖片 一頁10條
2.點擊 第二頁 發現上方的URL http://maoyan.com/board/4?offset=10
由此可見 offset代表偏移值
2.抓取首頁
import requests
def get_one_page(url):
headers ={
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.170 Safari/537.36',
}
response = requests.get(url,headers = headers)
if response.status_code ==200:
return response.text
return None
def main():
url = 'http://maoyan.com/board/4'
html = get_one_page(url)
print(html)
main()
3.正則提取
先觀察一個條目的源碼:
1.提取排名信息:
這裏可以寫成的正則表達式:<dd>.*?board-index.*?>(.*)</i> 發現可以一對標記只需要寫一個就可以
2.提取電影圖片
可以看到有兩個圖片鏈接,簡單的測試之後,就可以得到 data-src是電影圖片。
正則表達式可以寫爲:<dd>.*?board-index.*?>(.*)</li>.*?data-src = "(.*?)"
3.提取電影名稱
正則表達式 :<dd>.*?board-index.*?>(.*?)</li>.*?data-src="(.*?)".*?name.*?a.*?>(.*?)<a>
4.提取主演、發佈時間評分等內容 :
<dd>.*board-index.*?>(.*?)</i>.*?data-src="(.*?)".*?name.*?a.*?>(.*)</a>.*?star.*?>(.*?)</p>.*?releasetime.*?>(.*?)</p>.*?integer.*?>(.*?)</li>(.*?)</li>.*?fraction.*?>(.*)</li>.*?<dd>
第四個就是完整的正則表達式了,裏面匹配了七個信息。接下來調用findall方法提取所有內容。
def parse_one_page(html):
pattern = re.compile('<dd>.*board-index.*?>(.*?)</i>.*?data-src="(.*?)".*?name.*?a.*?>
+(.*)</a>.*?star.*?>(.*?)</p>.*?releasetime.*?>(.*?)</p>.*?integer.*?>(.*?)</li>(.*?)</li>.*?fraction.*?>(.*)</li>.*?<dd>','re.S')
items = re.findall(pattern,html)
print(items)
for item in items:
yield{
'index':'item[0]',
'image':'item[1]',
'title':item[2]strip()
'actor':item[3]strip()[3:] if len(item[3]) >3 else'',
'time':item[4]strip()[5:] if len(item[4])>5 else '',
'score':item[5].strip()+item[6].strip()
}
這樣就可以成功提取 電影的排名 圖片 標題 演員 時間 評分 等內容 並把它賦值爲一個字典 形成結構化數據
4.寫入文件
這裏直接寫入一個文本文件中。這裏通過JSON庫的dumps()方法實現字典的序列化,並指定ensure_ascii參數爲False,這樣就可以保證輸出結果是中文形式而不是Unicode編碼。
def write_to_file(content):
with open('result.txt','a',encoding='utf-8') as f:
print(type(json.dumps(content)))
f.write(json.dumps(content,ensure_ascii=False)+'\n')
5.整合代碼
最後,實現main()方法調用前面實現的方法,將單頁的電影結果寫入到文件。相關代碼如下:
def main()
url = 'http://maoyan.com/board/4'
html = get_one_page(url)
for item in parse_one_page(html)
write_to_file(item)
6.分頁爬取
因爲需要抓取的是top100的電影,所以還需要遍歷一下,給這個鏈接傳入offset參數,實現其他90部電影的爬取,此時添加如下調用 即可:
if __name__=='__main__':
for i in range(10):
main(offset=i*10)
這裏還需要將main()方法修改一下,接收一個offset值作爲偏移量,然後構造URL進行爬取。實現代碼如下:
def main(offset):
url = 'http://maoyan.com/board/4?offset='+str(offset)
html = get_one_page(url)
for item in parse_one_page(html):
print(item)
write_to_file(item)
7.完整代碼:
import json
import requests
from requests.exceptions import RequestException
import re
import time
def get_one_page(url):
try:
headers = {
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.162 Safari/537.36'
}
response = requests.get(url, headers=headers)
if response.status_code == 200:
return response.text
return None
except RequestException:
return None
def parse_one_page(html):
pattern = re.compile('<dd>.*?board-index.*?>(\d+)</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],
'image': item[1],
'title': item[2],
'actor': item[3].strip()[3:],
'time': item[4].strip()[5:],
'score': item[5] + item[6]
}
def write_to_file(content):
with open('result.txt', 'a', encoding='utf-8') as f:
f.write(json.dumps(content, ensure_ascii=False) + '\n')
def main(offset):
url = 'http://maoyan.com/board/4?offset=' + str(offset)
html = get_one_page(url)
for item in parse_one_page(html):
print(item)
write_to_file(item)
if __name__ == '__main__':
for i in range(10):
main(offset=i * 10)
time.sleep(1)
這個爬蟲是看着崔老師的書寫的,決定自己重新寫一遍,之後換一個網站爬一下。