閑話:
一位前輩告訴我大學期間要好好維護自己的博客,在博客園發布很好,但是自己最好也保留一個備份。
正好最近在學習python,剛剛從py2轉到py3,還有點不是很習慣,正想着多練習,於是萌生了這個想法——用爬蟲保存自己的所有文章
在查了一些資料后,慢慢的有了思路。

正文:
有了上面的思路后,編程就不是問題了,就像師傅說的,任何語言,語法只是很小的一部分,主要還是編程思想。於是邊看語法,邊寫程序,照葫蘆畫瓢,也算實現了既定的功能:
1、現在py文件同目錄下創建一個以博主名字為名的文件夾,用來存放爬取的所有文章。
2、暫時先保存成TXT文件,這個比較容易。但是缺點是無法保存圖片。后面在學習直接轉成PDF。
3、爬取完成后提醒我你爬取了多少片文章。
要懶就懶到位,最好不要讓我動一下手就自動爬取所有文章,但是。。。。還是要看一下自己的文章目錄的url吧、看一下自己有多少頁目錄吧,然后這兩個參數填進去之后,就完美了。
提示:使用chrome瀏覽器,在chrome下:先按F12進入開發者模式,在網頁上右鍵選中一塊區域,然后選擇【檢查】,在右側即可查看對應的HTML程序。
主要函數的實現:
1、獲取所有文章的url:
def get_urls(url,pages): """ 獲取所有目錄下的所有文章url :param url: 某一頁目錄的url,去掉最后的數字 :param pages: 一共需要爬取的頁數 :return: 返回所有文章url的列表 """ total_urls = [] for i in range(1,pages+1): #根據一個目錄的url找到所有目錄 url_temp = url + str(i) html = get_html(url_temp) #獲取網頁源碼 title_pattern = re.compile(r'<a.*?class="postTitle2".*?href="(.*?)">',re.S) #文章url正則表達式 url_temp2 = re.findall(title_pattern,html) #找到一個目錄中所有文章的網址 for _url in url_temp2: total_urls.append(_url) #所有文章url放在一起 return total_urls
關於正則表達式的選擇:這是我目錄中的兩篇文章標題的HTML程序:


可以發現,都在一對a標簽下,class屬性為:"postTitle n",其href屬性就是文章的url網址。
所以正則表達式可以寫為:re.compile(r'<a.*?class="postTitle2".*?href="(.*?)">',re.S)
最后調用append方法,將所有文章的url放在一個list列表里面。
2、獲取文章標題:
def get_title(url): """ 獲取對應url下文章的標題,返回標題 :param url: :return: """ html_page = get_html(url) title_pattern = re.compile(r'(<a.*id="cb_post_title_url".*>)(.*)(</a>)') title_match = re.search(title_pattern,html_page) title = title_match.group(2) return title
這個也很簡單,檢查元素我們可以發現:

與上面一樣,這個正則表達式可以選擇:re.compile(r'(<a.*id="cb_post_title_url".*>)(.*)(</a>)')
然后保留其第二個分組就是文章標題。
3、獲取正文:
def get_body(url): """ 獲取url下文章的正文內容 :param url: :return: """ html_page = get_html(url) soup = BeautifulSoup(html_page,'html.parser') #HTML文檔解析器 div = soup.find(id = "cnblogs_post_body") return div.get_text()
使用BeautifulSoup模塊,創建一個對象,然后使用 soup.find()方法,搜索ID為 "cnblogs_post_body" 的標簽,返回標簽內的文檔內容。

4、下載單個文件:
def save_single_file(url): """ 首先在py文件同目錄下創建一個以博主名字為名的文件,用來存放爬取的所有文章 將文章正文保存在txt文件中,名字為文章標題 有些文章的標題可能不適合直接作為txt文件名,我們可以忽略這些文章 :param url: :return: """ global article_count #使用全局變量,需要在函數中進行標識 title = get_title(url) body = get_body(url) #獲取當前目錄文件,截取目錄后,並自動創建文件 FILE_PATH = os.getcwd()[:-0]+author+'_''text\\' if not os.path.exists(FILE_PATH): os.makedirs(FILE_PATH) try: filename = title + '.txt' with open('D:\learning python\coding_python3.6\cnblog\\Andrew_text\\'+filename,'w',encoding='utf-8') as f: f.write(body) #正文寫入文件 article_count+= 1 #計數變量加1,統計總的下載文件數 except: pass print(title+" file have saved...") #提示文章下載完畢
對於 os.getcwd()方法,
如果a.py文件存放的路徑下為:D:\Auto\eclipse\workspace\Testhtml\Test
通過os.getcwd()獲取的路徑為:D:\Auto\eclipse\workspace\Testhtml\Test
使用os.getcwd()[:-4]截取到的路徑為:D:\Auto\eclipse\workspace\Testhtml\ ,注意這個-4是在當前目錄字符串下,向前截取4個字符后的目錄。不想截取的話,直接省略數字,但是要有 [:]
使用下面的命令則在3步驟下新建文件夾,名為:變量author_text:
#獲取當前目錄文件,截取目錄后,並自動創建文件 FILE_PATH = os.getcwd()[:-0]+author+'_''text\\' if not os.path.exists(FILE_PATH): os.makedirs(FILE_PATH)
5、最終下載:
def save_files(url,pages): """ 調用單個文件保存函數,循環保存所有文件 :param url:傳入任意一個目錄的url,但是要注意去掉最后的數字。 :return: """ total_urls = get_urls(url,pages) print("get all the urls..."+'\n') print(total_urls) #獲取的文章url正確 for urls in total_urls: save_single_file(urls) #輸出下載的總文章數 print('\n' + "total article count is :%d"%article_count)
運行結果:

參考資料:
項目啟發:http://www.cnblogs.com/xingzhui/p/7881905.html
正則表達式:https://blog.csdn.net/qq_878799579/article/details/72887612
