需求是將貼吧的【某個吧】里面【n頁】的網頁代碼爬取下來,保存至本地
首先我們要思考這個貼吧爬蟲的框架,要有方法可以構造url列表(就可以一次獲取多個url),能請求獲取相應,能把html保存到本地。
import requestsclass TiebaSpider(object): # 初始化核心組件def __init__(self): ....要有url要有headersdef 構造url列表(self): passdef 獲取響應(self): passdef 保存(self): passdef run(self): '''主要業務邏輯'''#url列表#發送請求獲取響應#保存if __name__ == '__main__': TiebaSpider=TiebaSpider()TiebaSpider.run()
一、初始化核心組件
找到貼吧某個吧【lol吧】的url: https://tieba.baidu.com/f?kw=lol&ie=utf-8&pn=450
pn是確定頁面的參數,450/50=9,0是第1頁,9是第10頁。怎么獲取【貼吧名字】,實例化對象的時候把參數寫里面去,然后在初始化方法里面,加上tieba_name去獲取傳的名字。
#將變量 tieba_name 綁定到當前類的實例上,使其成為實例變量,作用域貫穿實例的生命周期
self.tieba_name = tieba_name self.start_url = 'https://tieba.baidu.com/f?kw='+tieba_name+'&ie=utf-8&pn={}'self.headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36"
}
二、構造存放url列表的函數
需要構建一個空列表url_list = [] ,用來保存這10頁的 url ,這些url的參數是需要我們提供的,并且拼接起來,所以要思考怎么獲取【頁數】,每一頁是50條數據,所以第1頁是050,第2頁是150,依次類推用到range()方法,range是從0開始的,然后每一條的頁數信息也拼接上,url就完整了。
format()的基本功能作用:將變量值填充到字符串的{}占位符中。
def get_url_list(self):# 構造URL列表url_list = []for i in range(10): #循環10次,也就是10頁url_list.append(self.start_url.format(i*50)) # print(url_list) #檢測url寫對沒return url_list #然后返回url_list
run()函數里面也要調用這個 get_url_list()函數,把返回的url_list的值保存到變量url_list里面
#構造URL列表
url_list = self.get_url_list() #調用所以這個列表會保存到url_list里面
三、構造發送請求獲取響應的函數
想要得到響應,用到的就是requests.get(url)方法,保存到response變量里面,用response.text 或者 response.content.decode()獲取網頁源代碼內容【也就是html】,那我們的url怎么得到并能在這個函數里面使用?就需要在這個構造函數里面加一個參數url。
def parse_url(self,url):print(url)# 發送請求,得到響應response = requests.get(url,headers=self.headers)response.encoding = 'utf-8'return response.text #返回的值是網頁代碼
并且在run()里面要先循環存入 url_list 里面真實的 url 到 for循環的 變量url 里面,存的就是通過response.text獲得的html代碼,所以調用方法parse_url()保存到名為html的變量里面
#遍歷 發送請求獲取響應for url in url_list: #循環列表里元素個數的次數,然后每次把列表里面的元素按順序賦值給urlhtml = self.parse_url(url) #調用此方法傳參url,所以方法里面要接受url,參數要加上url# print(html)page_num = url_list.index(url) + 1 #index()前面的對象要是列表,url只是列表里面的一個元素,是一個str類型
這個時候其實還沒思考怎么傳頁數,后面再回頭寫page_num。現在也可以淺淺分析一下:因為在后面保存的時候,我需要頁面的參數來命名【tieba_name-第i頁.html】,所以這里的列表索引可以作為頁數,比定義一個page_num = 0,然后用for…range 循環保存頁數要高級,代碼量也少些。index下標是從0開始,所以第1頁就是 url_list.index(url) + 1 。注意index()括號里面寫的是列表里面的這個元素對應的下標,所以括號里面是變量url。
四、構造保存html的函數
保存的時候我要知道【貼吧名】,【網頁源代碼】和【頁數】,所以要把這些參數獲取到。而【貼吧名 self.tieba_name】是初始化里面加了self.的實例變量,可以在任何構造函數里面使用或修改,故不需要在函數里傳參(不需要在括號里面寫參數名)。在函數括號里面加上【網頁源代碼】和【頁數】這兩個參數名即可。
補充:實例變量(self.變量名):
通過 self.變量名 定義的變量屬于當前實例,作用域貫穿實例的生命周期。
其他方法也可以通過 self.變量名 訪問或修改它。
保存的HTML名字是這個類型:“ tieba_name-第i頁.html ”
def save_html(self,html,page_num):# 保存 tieba_name-第i頁.htmlwith open(self.tieba_name+'-第'+str(page_num)+'頁.html','w',encoding='utf-8') as f:f.write(html)
run() 方法里也要調用 save_html() 方法,因為 save_html() 方法 里面要獲取【網頁源代碼】和【頁數】,所以我們在調用 save_html() 方法 時候要傳入 html , page_num 兩個參數。
#保存
self.save_html(html,page_num) #調用此方法傳參html,所以方法里面要接受html,參數要加上html。然后把page_num傳給save_html()方法
五、爬蟲整體代碼
import requestsclass TiebaSpider(object): #集成object 面向對象def __init__(self,tieba_name): #init# 初始化核心組件 #https://tieba.baidu.com/f?kw=lol&ie=utf-8&pn=450 pn是頁面,一頁50條self.tieba_name = tieba_name #這樣才可以在別的方法里使用到傳過來的tieba_name,以 self.tieba_name 變量來使用self.start_url = 'https://tieba.baidu.com/f?kw='+tieba_name+'&ie=utf-8&pn={}'self.headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36"}def get_url_list(self):# 構造URL列表'''url_list = []for i in range(10): #10次10頁url_list.append(self.start_url.format(i*50)) # print(url_list) #檢測url寫對沒return url_list #然后返回url_list'''# 列表推導式(List Comprehension)是 Python 中一種簡潔高效的構建列表的方式,可以替代顯式的 for 循環和 append 操作。想要看結果也可以把推導式保存至變量,然后print出來return [self.start_url.format(i*50) for i in range(10)]def parse_url(self,url):print(url)# 發送請求,得到響應response = requests.get(url,headers=self.headers)response.encoding = 'utf-8'return response.text #返回的值是網頁代碼def save_html(self,html,page_num):# 保存 tieba_name-第i頁.html# print(page_num)with open(self.tieba_name+'-第'+str(page_num)+'頁.html','w',encoding='utf-8') as f:f.write(html)def run(self): #run方法'''主要業務邏輯'''#構造URL列表url_list = self.get_url_list() #調用所以這個列表會保存到url_list里面#遍歷 發送請求獲取響應for url in url_list: #循環列表里元素個數的次數,然后每次把列表里面的元素按順序賦值給urlhtml = self.parse_url(url) #調用此方法傳參url,所以方法里面要接受url,參數要加上url# print(html)page_num = url_list.index(url) + 1 #index()前面的對象要是列表,url只是列表里面的一個元素,是一個str類型#保存self.save_html(html,page_num) #調用此方法傳參html,所以方法里面要接受html,參數要加上html。然后把page_num傳給save_html()方法# exit() #循環第一次就退出if __name__ == '__main__': #mainTiebaSpider = TiebaSpider('lol') #實例化這個類 lol貼吧名TiebaSpider.run()
最終點擊html實現的效果,動手嘗試一下吧!