本文章主要是實現一個最基礎的網絡爬蟲框架,採用廣度優先策略,即先爬取當級的所有網頁,再對下級網頁進行爬取。這樣的文章可以說是一找一大堆,但我還是寫了一遍,別人寫的代碼,那是別人的東西,如果不親自實踐,那你是永遠都無法掌握,發出來也是想給初學者一個參考。還有救是每次寫超過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
運行結果