用python爬蟲爬取CSDN博主信息
一、項目介紹
爬取網(wǎng)址:CSDN首頁的Python、Java、前端、架構(gòu)以及數(shù)據(jù)庫欄目。簡單分析其各自的URL不難發(fā)現(xiàn),都是https://www.csdn.net/nav/+欄目名樣式,這樣我們就可以爬取不同欄目了。
以Python目錄頁為例,如下圖所示:
爬取內(nèi)容:每篇文章的博主信息,如博主姓名、碼齡、原創(chuàng)數(shù)、訪問量、粉絲數(shù)、獲贊數(shù)、評論數(shù)、收藏數(shù)
(考慮到周排名、總排名、積分都是根據(jù)上述信息綜合得到的,對后續(xù)分析沒實質(zhì)性的作用,這里暫不爬取。)
不想看代碼的朋友可直接跳到第三部分~
二、Selenium爬取
分析目錄頁可知文章是需要動態(tài)加載的,此時需要selenium模擬瀏覽器不斷下拉才能獲取新的文章。文章的鏈接如下所示:
1、第一種爬取思路(未果)
思路圖如下:
執(zhí)行的關(guān)鍵代碼如下:
from selenium import webdriver import time driver = webdriver.Chrome() driver.get('https://www.csdn.net/nav/python') #下拉若干次 for i in range(10): driver.execute_script('window.scrollTo(0,document.body.scrollHeight)') time.sleep(1) #定位所有鏈接 blog_url = driver.find_elements_by_css_selector('div.title > h2 > a') #注意:這里保存的是所有element對象 for i in range(len(blog_url)): url = blog_url[i].get_attribute('href') driver.get(url) #------------相關(guān)信息爬取(省略)---------- driver.back() #返回目錄頁
理論上,這段代碼看起來是可以實現(xiàn)要求的,但實際上會遇到以下兩個問題!
(1)元素定位問題
報錯的原因:selenium當打開新的頁面后,原來定位過的元素都會失效,需要重新定位元素。上面的driver.back()相當于打開的新的頁面(但是對于我們來說只是返回原來的頁面)
解決方式:只要每次返回目錄頁后重新定位元素即可,如下所示:
for i in range(len(blog_url)): blog_refind_url = driver.find_elements_by_css_selector('div.title > h2 > a') #重新定位 url = blog_refind_url[i].get_attribute('href') driver.get(url) #------------相關(guān)信息爬取(省略)---------- driver.back() #返回目錄頁
重新定位后,不難發(fā)現(xiàn),這必須要求blog_url和blog_refind_url這兩個列表的長度一致??!那也就是:每次返回目錄頁后,需要保持在上一次瀏覽的位置! 由此引發(fā)了第二個問題:定位元素的不一致。
(2)定位元素不一致
我們在獲取所有的文章鏈接之前,首先進行的下滑頁面的操作。而每次driver.back()之后,頁面都會回到最初的位置!這就很頭疼,如果要保持一樣的瀏覽位置,難道每次返回后都要下拉相同次數(shù)的頁面么?那么此時我們需要解決的問題則是:如何保持上一級頁面的瀏覽位置。emm,查了一些資料,發(fā)現(xiàn)這個需求是和javascript相關(guān)的。詳細可參考這篇博客:js:返回到頁面時滾動到上次瀏覽位置
大致解決思路:保存每次下滑的位置,然后最終調(diào)用最后一次下滑的位置。但歸根到底,還是需要每次滑動頁面,依舊很麻煩,這種思路到這也只能不了了之了。(會javascript的朋友可以嘗試如何讓頁面直接恢復到上一級頁面瀏覽的位置)
2、第二種爬取思路(成功)
不過,仔細思考一下,上面兩個問題的來源關(guān)鍵在于selenium訪問頁面后,元素會重新定位。而我們第一步定位所有文章鏈接時保存的列表,里面的元素都是element對象(它是會隨著頁面變化而改變的!)。所以,我們只要保存每個文章的url到一個列表,挨個訪問每個url,不就可以了?
思路圖如下:
兩種思路的對比與思考:前者裝有所有文章的列表里都是element對象,而后者裝有所有文章的列表里都是url。后者免去了再返回頁面這一操作,相當于將一個爬取二級頁面問題轉(zhuǎn)化為一級頁面問題!
全部代碼如下:
from selenium import webdriver import os os.chdir('C:/Users/dell/Desktop') import time import pandas as pd def scroll_down(driver,num): for i in range(num): driver.execute_script('window.scrollTo(0,document.body.scrollHeight)') time.sleep(1) def save_data(df): data=pd.DataFrame(df,columns=['blog_name','code_time','blog_num', 'view_num','fans_num','likes_num', 'comments_num','collections_num']) data.to_csv('csdn_user.csv',index=False,encoding='gb18030') def crawler_csdn(parts_list): opt = webdriver.ChromeOptions() opt.add_experimental_option('excludeSwitches',['enable-automation']) opt.add_argument('--headless') opt.add_argument('--disable-gpu') opt.add_argument('blink-settings=imagesEnabled=false') driver = webdriver.Chrome(options=opt) df = [] for part in parts_list: count=0 url_des='https://www.csdn.net/nav/'+part driver.get(url_des) scroll_down(driver,30) time.sleep(2) print('開始爬取{}部分'.format(part)) blog_list=[] blog_url = driver.find_elements_by_css_selector('div.title > h2 > a') for url in blog_url: blog_list.append(url.get_attribute('href')) print('共{}個博主'.format(len(blog_list))) for i in range(len(blog_list)): try: driver.get(blog_list[i]) blog_name = driver.find_element_by_css_selector('div.profile-intro-name-boxTop > a >span.name').text code_time = driver.find_element_by_css_selector('span.personal-home-page.personal-home-years').text blog_num = driver.find_element_by_css_selector( 'div.data-info.d-flex.item-tiling>dl.text-center>a>dt>span.count').text inf_list = driver.find_elements_by_css_selector('div.data-info.d-flex.item-tiling>dl.text-center>dt>span.count') df.append([blog_name, code_time, blog_num, inf_list[0].text, inf_list[2].text, inf_list[3].text, inf_list[4].text, inf_list[5].text]) count += 1 print('第{}個博主信息爬取完成'.format(count)) except: print('相關(guān)信息不全') print('{}部分爬取完成'.format(part)) return df if __name__ =='__main__': start = time.time() parts_list=['Python','Java','web','arch','db'] df = crawler_csdn(parts_list) save_data(df) end = time.time() spend_time = int((end-start)/60) print('共花費{}分鐘'.format(spend_time))
爬取結(jié)果如下:
三、Webscraper爬取
之前的博客分享過Webscraper是一種輕量級的爬取軟件。不想看代碼的朋友可以用它來復現(xiàn)上述爬取過程。(注:以下爬取過程只是針對首頁的某一個欄目)
最終的爬取線路圖如下
依舊以首頁的Python欄為例:
1、創(chuàng)建下拉對象
這個container只是一個ID,它可以取任意名字的。其他的設(shè)置如下圖所示:
Type勾選Element_scroll_down(負責下拉頁面)勾選上Multiple后,點擊多個文章所在模塊后,則會出現(xiàn)紅色選定。此時點擊Done selecting,完成selector的配置。Delay設(shè)置為2000毫秒(給予頁面反應(yīng)時間)
此外,需要在selector后面加上:nth-of-type(-n+300)
,控制爬取的條數(shù),否則它會一直下拉頁面?。ㄟ@里的300則代表需要爬取的總條數(shù))最終,selector的配置如下:
2、創(chuàng)建文章鏈接對象
保存container的selector后,點擊進入下一層,創(chuàng)建如下selector
具體內(nèi)容如下:
Type選擇LinkSelector中不勾選Multiple,h2 a則是文章鏈接定位的位置
Link不方便定位的話,可以先選擇text進行定位,然后得到位置后,再復制到link這即可。
3、創(chuàng)建博主信息對象
同理,保存完inf的selector后,再點擊進入下一層,依次創(chuàng)建各類信息的selector,如下所示:
以name為例,其內(nèi)容如下:
type選擇text,相應(yīng)的選擇器內(nèi)容只要鼠標點擊博主姓名即可獲得。
這樣,我們就完成了所有的準備工作,接下來就可爬取啦~所有延遲時間均設(shè)置為2000ms
最終爬取結(jié)果如下(這里僅作演示,只爬取了七條):
本次創(chuàng)建的sitemap如下,有興趣的朋友可以自己實驗下,只需要import sitemap即可
{"startUrl":"https://blog.csdn.net/nav/python","selectors":[{"parentSelectors": ["_root"],"type":"SelectorElementScroll","multiple":true,"id":"container","selector":"ul.feedlist_mod li.clearfix:nth-of-type(-n+300)","delay":"2000"},{"parentSelectors": ["container"],"type":"SelectorLink","multiple":false,"id":"inf","selector":"h2 a","delay":""},{"parentSelectors": ["inf"],"type":"SelectorText","multiple":false,"id":"name","selector":"div.profile-intro-name-boxTop span.name","regex":"","delay":""},{"parentSelectors": ["inf"],"type":"SelectorText","multiple":false,"id":"blog_num","selector":"dl.text-center:nth-of-type(1) a span.count","regex":"","delay":""},{"parentSelectors": ["inf"],"type":"SelectorText","multiple":false,"id":"code_time","selector":"span.personal-home-page.personal-home-years","regex":"","delay":""},{"parentSelectors": ["inf"],"type":"SelectorText","multiple":false,"id":"views_num","selector":"div.data-info:nth-of-type(2) dl.text-center > dt span.count","regex":"","delay":""},{"parentSelectors": ["inf"],"type":"SelectorText","multiple":false,"id":"fans","selector":"dl#fanBox.text-center span.count","regex":"","delay":""},{"parentSelectors": ["inf"],"type":"SelectorText","multiple":false,"id":"agreement","selector":"dl.text-center:nth-of-type(3) > dt span.count","regex":"","delay":""},{"parentSelectors": ["inf"],"type":"SelectorText","multiple":false,"id":"comment","selector":"div.data-info:nth-of-type(4) dl.text-center:nth-of-type(4) span.count","regex":"","delay":""},{"parentSelectors":["inf"],"type":"SelectorText","multiple":false,"id":"collection_num","selector":"dl.text-center:nth-of-type(5) span.count","regex":"","delay":""}],"_id":"csdn"}
總結(jié):Webscraper雖然簡單易操作,速度也和selenium差不多,但每次只能爬一個網(wǎng)址,需要連續(xù)爬取多個網(wǎng)址,還是得碼代碼~
以上就是使用python快速爬取CSDN博主信息的詳細內(nèi)容,更多關(guān)于python爬取CSDN博主信息的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Python內(nèi)置函數(shù)delattr的具體用法
本篇文章主要介紹了Python內(nèi)置函數(shù)delattr的具體用法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-11-11Python的ORM框架中SQLAlchemy庫的查詢操作的教程
這篇文章主要介紹了Python的ORM框架中SQLAlchemy庫的查詢操作的教程,SQLAlchemy用來操作數(shù)據(jù)庫十分方便,需要的朋友可以參考下2015-04-04Python編程中實現(xiàn)迭代器的一些技巧小結(jié)
只談迭代器的話在Python中只是一個泛指的概念,具體的可以用yield、生成器表達式、iter等多種方式來構(gòu)建,這里我們整理了Python編程中實現(xiàn)迭代器的一些技巧小結(jié):2016-06-06對Python通過pypyodbc訪問Access數(shù)據(jù)庫的方法詳解
今天小編就為大家分享一篇對Python通過pypyodbc訪問Access數(shù)據(jù)庫的方法詳解,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-10-10使用Python實現(xiàn)將數(shù)據(jù)寫入Excel工作表
在數(shù)據(jù)處理和報告生成等工作中,Excel?表格是一種常見且廣泛使用的工具,本文中將介紹如何使用?Python?寫入數(shù)據(jù)到?Excel?表格,并提供更高效和準確的?Excel?表格數(shù)據(jù)寫入方案,需要的可以參考下2024-01-01