一、前言
其實爬取頁面的思路都差不多,觀察爬取頁面源碼,獲取頁面內(nèi)容,根據(jù)源碼的格式規(guī)律將自己需要的內(nèi)容提取出來,提取后美化輸出或者保存!
之前寫過了如何爬取淘寶和京東的評論,其實這個可以不寫的!!但是又遇到坑了所以還是寫下來,記錄一下錯誤??!
二、代碼與問題
先上代碼再說一下自己遇到的問題!
# -*- coding:utf-8 -*-
import requests
from requests.exceptions import RequestException
import re
import json
import time
from multiprocessing import Pool
"""
url= 'https://maoyan.com/board/4'
repsponse = requests.get(url)
print(repsponse.headers['content-type'])
print(repsponse.encoding)#response內(nèi)容的編碼
print(repsponse.apparent_encoding)#response headers里設置的編碼
print(requests.utils.get_encodings_from_content(repsponse.text))#response返回的html header標簽里設置的編碼
"""
def get_url(url):
try:
#說明headers信息,不然一下就403錯誤了!
heards = {'user-agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36'}
#獲取頁面信息
response = requests.get(url,headers=heards)
#頁面返回的status_code碼為200則是爬取成功
if response.status_code == 200:
#聲明頁面返回內(nèi)容的編碼格式,不然一般是ISO-8859-1,就亂碼了
response.encoding = 'utf-8'
return response.text
return print("爬取失敗")
except RequestException:
return print("爬取失敗")
def parge_html(html):
#編寫正則表達式的格式
#compile() 函數(shù)將一個字符串編譯為字節(jié)代碼
pattern = re.compile('<dd>.*?board-index.*?(\d+).*?name.*?<a.*?>(.*?)</a>.*?star">(.*?)</p>.*?releasetime">'
+'(.*?)</p>.*?integer">(.*?)</i>.*?fraction">(\d+)</i>.*?</dd>',re.S)
#利用正則表達式獲取需要的內(nèi)容
items = re.findall(pattern,html)
#print(items)
#將內(nèi)容轉(zhuǎn)化為一個字典使其更容易觀看
for item in items:
yield{
'index':item[0],
'name':item[1],
'star':item[2].strip()[3:], #strip() 方法用于移除字符串頭尾指定的字符(默認為空格或換行符)或字符序列。
'time':item[3][5:],
'score':item[4]+item[5]
}
def write_to_file(content):
with open('result1.txt', 'a', encoding='utf-8') as f:
#ensure_ascii=False,說明輸出的內(nèi)容不要用ASCII編碼,這樣結(jié)果才是中文
f.write(json.dumps(content,ensure_ascii=False) + '\n') #利用json.dumps將字典轉(zhuǎn)為字符串
f.close()
def main(offset):
#切換頁面觀察URL的變化
url = 'https://maoyan.com/board/4?offset=' + str(offset)
html = get_url(url)
for item in parge_html(html):
print(item)
write_to_file(item)
#print(html)
if __name__ == "__main__":
#單線程爬取
"""
for i in range(10):
time.sleep(10)
main(i*10)
"""
#多線程
pool = Pool(processes = 10) #默認的話進程數(shù)為cpu_count()的值
pool.map(main,[i*10 for i in range(10)])
問題1:
我最開始寫的是爬取一頁的電影內(nèi)容,沒有用正則表達式轉(zhuǎn)化提取,但是輸出的內(nèi)容是亂碼的!
既然亂碼就是編碼問題了,由于我是已經(jīng)聲明utf-8的編碼模式了,我以為是軟件問題,我是用pycharm(第一次用我也不知道它初始編碼是什么,之前一直用Spyder),我查了一下怎么修改pycharm的編碼,file—>settings—>Editor—>File Encoding,一看那里有一個是gbk,我就都改為了utf-8!

但是重新輸出后還是亂碼??!
在網(wǎng)上找了好久,終于看到有一篇說到點了,其他大部分要么教我修改pycharm編碼要么在程序一開始聲明utf-8但是都沒用!
原來是因為在你調(diào)用Response.text時對響應進行解碼,如果http頭部有聲明則基本上按聲明進行解碼,沒用它就會猜!使用默認的 ISO-8859-1解碼,有時http頭部聲明了也還是按照這個解碼!
print(repsponse.encoding)#response內(nèi)容的編碼
print(repsponse.apparent_encoding)#response headers里設置的編碼
print(requests.utils.get_encodings_from_content(repsponse.text))#response返回的html header標簽里設置的編碼
可以輸入上面的代碼看一下是不是編碼出問題,我的輸出是:ISO-8859-1,utf-8,utf-8請求返回的內(nèi)容變成了ISO-8859-1肯定亂碼!
可以在獲取內(nèi)容后先輸入:
response.encoding = 'utf-8'
聲明請求返回內(nèi)容是utf-8編碼。
問題2:
問題1解決后我又爬了一次!這次沒有亂碼,但是因為我在調(diào)整編碼的時候一直測試一直爬,貓眼覺得我的請求很可疑!禁止了我的請求,出現(xiàn)了403錯誤!
這個通過增加一個頭部信息就好了,之前淘寶比較嚴格,頭部信息比較多。這次就加了一個請求的瀏覽器類型就可以了!
問題3:
問題2解決后,我接著完善,剛剛是爬取一頁,現(xiàn)在是十頁!但是又出問題了爬的太頻繁太快被要求驗證身份了,也就是類似拼圖,但是我爬取的內(nèi)容還沒完呢!少了一頁,所以我又加了睡眠信息,每十秒爬一次,終于成功了!這是單線程!
接下來是多線程爬?。憾嗑€程一般默認是cpu_count()數(shù),我的是8,但是我自己定義開了十個進程。
天下武功唯快不破?。?!用了十個進程秒爬,估計貓眼沒反應過來,最后爬取內(nèi)容缺了一個而已!
但是多線程有一個缺點,就是爬取的內(nèi)容不是按順序的,本來是top100的電影從1-100,多線程的話內(nèi)容有點亂!但是問題不大,因為它很快就好了。
參考:https://www.bilibili.com/video/BV1Si4y1s7S4?p=14
https://www.runoob.com/python/python-func-compile.html
https://www.runoob.com/python/att-string-strip.html
https://www.cnblogs.com/biangbiang/archive/2013/02/19/2916780.html
https://blog.csdn.net/a491057947/article/details/47292923
https://blog.csdn.net/weixin_43877278/article/details/103880644