Python 網絡爬蟲 迷你爬蟲框架

本文章主要是實現一個最基礎的網絡爬蟲框架,採用廣度優先策略,即先爬取當級的所有網頁,再對下級網頁進行爬取。這樣的文章可以說是一找一大堆,但我還是寫了一遍,別人寫的代碼,那是別人的東西,如果不親自實踐,那你是永遠都無法掌握,發出來也是想給初學者一個參考。還有救是每次寫超過50行的代碼我都會做流程圖,雖然很不標準,但還是可以有一個基本思路。有流程圖說明代碼中有自己的思考,還是那句話,寫程序,百分之80的時間用於思考,百分之20的時間用於寫代碼,你越是學你就越能體會到這句話的重要性。閒話到此爲止,我直接放流程圖和代碼,多的也不贅述,學能力是程序員最大的能力,自己研究吧

基本流程

運行主線程,進行初始化(實例化load_config類,讀取配置文件,依次實例化其他對象)

開啓多條爬蟲線程,爬蟲線程會從queue取出url,爬取url

將爬取並解析好的web傳入find_url,進行下級url的查找

save_url將爬取的url進行保存

當queue空後,且裝有爬取url的容器不爲空,則深度加1,並對下一級網頁進行爬取


代碼

main_thread.py

import queue
import crawl_url
import find_url
import save_url
import load_config


def main():
	#初始化對象
	Load_Config=load_config.LoadConfig()
	#加載配置文件
	Load_Config.load()
	Save_Url=save_url.SaveUrl(Load_Config.output_file)
	Find_Url=find_url.FindUrl()
	url_queue=queue.Queue()
	#放置現在需要爬取的網頁
	target_url=[]
	target_url.append(Load_Config.target_url)
	#放置已經爬取的網頁
	loaded_url=[]
	
	
	#加載並運行多個爬蟲線程
	for i in range(Load_Config.thread_count):
		Crawl_Url=crawl_url.CrawlUrl(url_queue,Save_Url,Find_Url,Load_Config,target_url,loaded_url)
		#主線程結束時,子線程立即結束
		Crawl_Url.setDaemon(True)
		#爬蟲線程開始
		Crawl_Url.start()
	
	#開始向隊列添加url
	#當前爬取深度
	cur_depth=0
	#判斷是否達到最大爬取深度
	while cur_depth<Load_Config.max_depth:
		#判斷隊列是否爲空,爲空向隊列添加url
		if url_queue.empty() and len(target_url)!=0:
			for each in target_url:
				url_queue.put(each)
				#刪除已經至queue的url
				target_url.remove(each)
			cur_depth+=1
			url_queue.join()
	print('爬蟲結束。。。。。。')

if __name__ =='__main__':
    main()

crawl_url.py

from bs4 import BeautifulSoup
import urllib.request
import urllib.error
import logging
import main_thread
import threading
#import find_url
#import save_url

logging.basicConfig(filename='log.txt',level=logging.NOTSET)

class CrawlUrl(threading.Thread):
	def __init__(self,queue,Save_Url,Find_Url,Load_Config,target_url,loaded_url):
		threading.Thread.__init__(self)
		self.queue=queue
		self.Save_Url=Save_Url
		self.Find_Url=Find_Url
		#爬蟲線程延遲
		self.Load_Config=Load_Config
		self.target_url=target_url
		self.loaded_url=loaded_url
		
	
	def run(self):
		while True:
			#從queue中取出url
			url=self.queue.get()
			#將此已經取出的url放入loaded_url容器
			self.loaded_url.append(url)
			print(url)
			try:
				#打開url
				respond=urllib.request.urlopen(url,data=None,timeout=self.Load_Config.thread_timeout)
				#用beatuiful對網頁編碼進行解析
				respond=BeautifulSoup(respond.read(),'html.parser')
				#提取該網頁的下級url
				href_list=self.Find_Url.find(respond)
				self.target_url.extend(href_list)
				#篩選重複的url
				self.target_url=set(self.target_url)
				self.target_url=list(self.target_url)
				self.Save_Url.save(href_list)
			except urllib.error.HTTPError as e:
				logging.debug("HTTPError: %s" % e.code)
			except urllib.error.URLError as e:
				logging.debug("URLError:%s" % e.reason)
			except Exception as e:
				logging.debug("Exception:%s" % e)
			finally:
				self.queue.task_done()

load_url.py

from configparser import ConfigParser

class LoadConfig():
	def __init__(self):
		#放置現在需要爬取的網頁
		self.target_url=''
		#urls存儲路徑
		self.output_file=[]
		#最大爬取深度
		self.max_depth=0
		#爬蟲線程延遲
		self.thread_interval=0
		#爬蟲線程超時時間
		self.thread_timeout=0
		#爬蟲線程數
		self.thread_count=0
		
	def load(self,filename='config.conf'):
		#創建ConffigParser對象
		conf=ConfigParser()
		#讀取配置文件
		conf.read(filename,encoding='utf-8')
		#加載配置
		self.target_url=conf.get('configuration','url')
		self.output_file=conf.get('configuration','output_file')
		self.max_depth=int(conf.get('configuration','max_depth'))
		self.thread_interval=int(conf.get('configuration','thread_interval'))
		self.thread_timeout=float(conf.get('configuration','thread_timeout'))
		self.thread_count=int(conf.get('configuration','thread_count'))
		
		print(".....................................")
		print("target_url:",self.target_url)
		print("output_file:",self.output_file)
		print("max_depth:",self.max_depth)
		print("thread_interval:",self.thread_interval)
		print("thread_timeout:",self.thread_timeout)
		print("thread_count:",self.thread_count)
		
		
if __name__=="__main__":
	config=LoadConfig()
	config.load()

find_url.py

import re
from bs4 import BeautifulSoup
import urllib.request

class FindUrl():
	def __init__(self):
		#創建篩選href的正則表達式
		self.pat=re.compile('href=\"([^"]*)\"')
		
		
	def find(self,respond):
		#創建用來存url的list
		href_list=[]
		#尋找所以a標籤
		tag_a=respond.findAll('a')
		for each in tag_a:
			#從a標籤中篩選href
			href=self.pat.search(str(each))
			#判斷是否匹配到href
			if href is None:
				continue
			
			href=href.group(1)
			#將herf添加至list
			href_list.append(href)
		
		#返回url列表
		return set(href_list)
		
			

if __name__ =='__main__':
	url = urllib.request.urlopen(r'http://www.supreme007.com/', data=None,timeout=10)
	response = BeautifulSoup(url.read(), "html.parser")
	find_url=FindUrl()
	urls=[]
	urls=find_url.find(response)
	urls=set(urls)
	for each in urls:
		print(each)

save_url.py

import logging
import time

logging.basicConfig(filename='log.txt',level=logging.NOTSET)

class SaveUrl():
	def __init__(self,output_file):
		self.output_file=output_file
		#記錄已經保存的urls
		self.urls_saved=[]
		
	def save(self,loaded_url):
		#去除已經保存過的url
		for each in self.urls_saved:
			loaded_url.remove(each)
		#保存urls
		try:
			file=open(self.output_file,mode='a',encoding='utf-8')
			for url in loaded_url:
				file.write(url+'\n')
				self.urls_saved.append(url)
			file.close()
		except IOError as error:
			logging.debug('IOError: '+error)
			
if __name__=='__main__':
	urls=['www.baidu.com','www.google.com','www.yahoo.com','www.google.com']
	saveurl=SaveUrl('C:/Users/Administrator/Desktop/1.txt')
	saveurl.save(urls)

config.conf

[configuration]
url:http://www.supreme007.com/
output_file:./output/urls.txt
max_depth:2
thread_interval:1
thread_timeout:10
thread_count:5

運行結果

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章