前言
前些天發(fā)現(xiàn)了一個巨牛的人工智能學(xué)習(xí)網(wǎng)站,通俗易懂,風(fēng)趣幽默,忍不住分享一下給大家:https://www.captainbed.cn/z
「個人網(wǎng)站」:雪碧的個人網(wǎng)站
ChatGPT體驗(yàn)地址
爬蟲
爬蟲是指一種自動化程序,能夠模擬人類用戶在互聯(lián)網(wǎng)上瀏覽網(wǎng)頁、抓取網(wǎng)頁內(nèi)容、提取數(shù)據(jù)等操作。爬蟲通常用于搜索引擎、數(shù)據(jù)挖掘、網(wǎng)絡(luò)分析、競爭情報(bào)、用戶行為分析等領(lǐng)域。
我們以爬取某個用戶的博文列表并存儲到文件中實(shí)現(xiàn)多線程爬蟲為例,帶大家體驗(yàn)爬蟲的魅力
獲取cookie
首先我們在爬取網(wǎng)站的時候首先獲取cookie
拿我的博客主頁為例,用F12打開控制臺,點(diǎn)擊網(wǎng)絡(luò),找到cookie
創(chuàng)建一個cookie文件,復(fù)制進(jìn)去
然后從給定的cookie_path文件中讀取cookie信息,并將其存儲在一個字典中。函數(shù)返回這個字典。
具體如下
def get_headers(cookie_path:str):
cookies = {}
with open(cookie_path, "r", encoding="utf-8") as f:
cookie_list = f.readlines()
for line in cookie_list:
cookie = line.split(":")
cookies[cookie[0]] = str(cookie[1]).strip()
return cookies
網(wǎng)站爬取與啟動
CSDN爬蟲
class CSDN(object):
def init(self, username, folder_name, cookie_path):
# self.headers = {
# "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.70 Safari/537.36"
# }
self.headers = get_headers(cookie_path)
self.s = requests.Session()
self.username = username
self.TaskQueue = TaskQueue()
self.folder_name = folder_name
self.url_num = 1
headers
: 這是一個字典,用于存儲請求頭信息。s
: 這是一個會話對象,用于保持與CSDN網(wǎng)站的連接。username
: 這是一個字符串,表示CSDN用戶的用戶名。TaskQueue
: 這是一個任務(wù)隊(duì)列對象,用于管理待訪問的URL。folder_name
: 這是一個字符串,表示保存爬取結(jié)果的文件夾名稱。_name
: 這是一個整數(shù),表示當(dāng)前保存的文件夾編號。_num
: 這是一個整數(shù),表示當(dāng)前爬取的頁面編號。
爬蟲啟動
def start(self):
num = 0
articles = [None]
while len(articles) > 0:
num += 1
url = u'https://blog.csdn.net/' + self.username + '/article/list/' + str(num)
response = self.s.get(url=url, headers=self.headers)
html = response.text
soup = BeautifulSoup(html, "html.parser")
articles = soup.find_all('div', attrs={"class":"article-item-box csdn-tracking-statistics"})
for article in articles:
article_title = article.a.text.strip().replace(' ',':')
article_href = article.a['href']
with ensure_memory(sys.getsizeof(self.TaskQueue.UnVisitedList)):
self.TaskQueue.InsertUnVisitedList([article_title, article_href])
- 初始化一個變量
num
,用于表示當(dāng)前訪問的文章頁碼。- 初始化一個列表
articles
,用于存儲待處理的文章信息。- 使用一個
while
循環(huán),當(dāng)articles
列表中的文章數(shù)量大于0時,執(zhí)行循環(huán)體。- 更新
num
變量,表示當(dāng)前訪問的文章頁碼。- 構(gòu)造一個URL,該URL包含當(dāng)前用戶名、文章列表和頁碼。
- 使用
requests
庫發(fā)送請求,并獲取響應(yīng)。- 使用
BeautifulSoup
庫解析HTML內(nèi)容,并提取相關(guān)的文章信息。- 遍歷提取到的文章列表,提取文章標(biāo)題和鏈接。
- 將文章標(biāo)題和鏈接插入到任務(wù)隊(duì)列
TaskQueue
的未訪問列表中。
將爬取內(nèi)容存到文件中
- 打印爬取開始的信息。
- 計(jì)算并獲取存儲博文列表的文件路徑。
- 使用
open
函數(shù)以寫入模式打開文件,并設(shè)置文件編碼為utf-8
。 - 寫入文件頭,包括用戶名和博文列表。
- 遍歷任務(wù)隊(duì)列
TaskQueue
中的未訪問列表,將每篇文章的標(biāo)題和鏈接寫入文件。 - 在每篇文章標(biāo)題和鏈接之間添加一個空行,以提高可讀性。
- 更新一個變量
_num
,用于表示當(dāng)前已寫入的文章序號。
代碼如下
def write_readme(self):
print("+"*100)
print("[++] 開始爬取 {} 的博文 ......".format(self.username))
print("+"*100)
reademe_path = result_file(self.username,file_name="README.md",folder_name=self.folder_name)
with open(reademe_path,'w', encoding='utf-8') as reademe_file:
readme_head = "# " + self.username + " 的博文\n"
reademe_file.write(readme_head)
for [article_title,article_href] in self.TaskQueue.UnVisitedList[::-1]:
text = str(self.url_num) + '. [' + article_title + ']('+ article_href +')\n'
reademe_file.write(text)
self.url_num += 1
self.url_num = 1
列表文件生成之后,我們要對每一個鏈接進(jìn)行處理
def get_all_articles(self):
try:
while True:
[article_title,article_href] = self.TaskQueue.PopUnVisitedList()
try:
file_name = re.sub(r'[\/::*?"<>|]','-', article_title) + ".md"
artical_path = result_file(folder_username=self.username, file_name=file_name, folder_name=self.folder_name)
md_head = "# " + article_title + "\n"
md = md_head + self.get_md(article_href)
print("[++++] 正在處理URL:{}".format(article_href))
with open(artical_path, "w", encoding="utf-8") as artical_file:
artical_file.write(md)
except Exception:
print("[----] 處理URL異常:{}".format(article_href))
self.url_num += 1
except Exception:
pass
- 從任務(wù)隊(duì)列
TaskQueue
中彈出未訪問的文章鏈接和標(biāo)題。- 嘗試獲取一個文件名,該文件名由文章標(biāo)題生成,以避免文件名中的特殊字符。
- 計(jì)算并獲取存儲文章的文件路徑。
- 創(chuàng)建一個Markdown文件頭,包括文章標(biāo)題。
- 獲取文章內(nèi)容,并將其添加到Markdown文件頭。
- 將處理后的Markdown內(nèi)容寫入文件。
- 打印正在處理的URL。
- 更新一個變量
_num
,用于表示已處理的文章數(shù)量。
多線程爬蟲
實(shí)現(xiàn)多線程爬蟲,以提高爬取速度。在循環(huán)中,會不斷地創(chuàng)建新的線程來處理任務(wù)隊(duì)列中的任務(wù),直到任務(wù)隊(duì)列為空。這樣可以充分利用計(jì)算機(jī)的多核性能,提高爬取效率。
def muti_spider(self, thread_num):
while self.TaskQueue.getUnVisitedListLength() > 0:
thread_list = []
for i in range(thread_num):
th = threading.Thread(target=self.get_all_articles)
thread_list.append(th)
for th in thread_list:
th.start()
我們在多線程爬蟲的時候,要保證系統(tǒng)有足夠的內(nèi)存空間。通過使用contextlib
庫的contextmanager
裝飾器,可以輕松地實(shí)現(xiàn)上下文管理,確保內(nèi)存分配和釋放的正確性。
lock = threading.Lock()
total_mem= 1024 * 1024 * 500 #500MB spare memory
@contextlib.contextmanager
def ensure_memory(size):
global total_mem
while 1:
with lock:
if total_mem > size:
total_mem-= size
break
time.sleep(5)
yield
with lock:
total_mem += size
在__enter__
方法中,使用with lock語句模擬加鎖,確保在執(zhí)行內(nèi)存分配操作時,不會發(fā)生競爭條件。然后判斷當(dāng)前系統(tǒng)的總內(nèi)存是否大于所需分配的內(nèi)存空間,如果大于,則減少總內(nèi)存,并跳出循環(huán)。
選擇要爬取的用戶
def spider_user(username: str, cookie_path:str, thread_num: int = 10, folder_name: str = "articles"):
if not os.path.exists(folder_name):
os.makedirs(folder_name)
csdn = CSDN(username, folder_name, cookie_path)
csdn.start()
th1 = threading.Thread(target=csdn.write_readme)
th1.start()
th2 = threading.Thread(target=csdn.muti_spider, args=(thread_num,))
th2.start()
- 檢查文件夾
folder_name
是否存在,如果不存在,則創(chuàng)建該文件夾。 - 創(chuàng)建一個CSDN對象
csdn
,用于模擬用戶登錄和爬取文章。 - 創(chuàng)建一個線程
th1
,目標(biāo)為_readme
。 - 創(chuàng)建一個線程
th2
,目標(biāo)為_spider
,并傳入?yún)?shù)(thread_num,)
,用于指定線程數(shù)量。
這個函數(shù)的目的是爬取指定用戶的CSDN博客文章,并將文章保存到文件夾folder_name
中。通過創(chuàng)建線程,可以實(shí)現(xiàn)多線程爬蟲,提高爬取速度。文章來源:http://www.zghlxwxcb.cn/news/detail-800400.html
線程池
線程池存儲爬蟲代理 IP 的數(shù)據(jù)庫或集合。在網(wǎng)絡(luò)爬蟲中,由于目標(biāo)網(wǎng)站可能會針對同一 IP 地址的訪問頻率進(jìn)行限制,因此需要使用池來存儲多個代理 IP 地址,以實(shí)現(xiàn) IP 地址的輪換和代理。池可以提高爬蟲的穩(wěn)定性和效率,避免因?yàn)?IP 地址被封禁而導(dǎo)致的爬蟲失效。
爬蟲和池是爬蟲領(lǐng)域中不可或缺的概念,池能夠提高爬蟲的穩(wěn)定性和效率,同時幫助爬蟲更好地適應(yīng)目標(biāo)的反爬蟲策略。文章來源地址http://www.zghlxwxcb.cn/news/detail-800400.html
到了這里,關(guān)于Python多線程爬蟲——數(shù)據(jù)分析項(xiàng)目實(shí)現(xiàn)詳解的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!