用Python 给你的个人微信朋友圈数据生成一本电子书吧!
簡介
微信朋友圈保留著你的數據,它留住了美好的回憶,記錄了我們成長的點點滴滴。發朋友圈從某種意義上來講是在記錄生活,感受生活,并從中看到了每個人每一步的成長。
這么一份珍貴的記憶,何不將它保存下來呢?只需一杯咖啡的時間,即可一鍵打印你的朋友圈。它可以是紙質書,也可以是電子書,可以長久保存,比洗照片好,又有時間足跡記憶。
- 這本書,可以用來:
- 送給孩子的生日禮物
- 送給伴侶的生日禮物
- 送給未來的自己
- ……
現在,你可以選擇打印電子書或者紙質書。打印紙質書的話,可以找第三方機構花錢購買;打印電子書的話,我們完全可以自己動手生成,這可以省下一筆不小的開支。
部分截圖
在開始寫代碼思路之前,我們先看看最終生成的效果。
電子書效果
[外鏈圖片轉存失敗(img-TH9tBgCt-1566632687224)(https://raw.githubusercontent.com/shengqiangzhang/examples-of-web-crawlers/master/10.%E4%B8%80%E9%94%AE%E7%94%9F%E6%88%90%E4%B8%AA%E4%BA%BA%E5%BE%AE%E4%BF%A1%E6%9C%8B%E5%8F%8B%E5%9C%88%E6%95%B0%E6%8D%AE%E7%94%B5%E5%AD%90%E4%B9%A6/image/page1.png)]
[外鏈圖片轉存失敗(img-Q117HJ9K-1566632687225)(https://raw.githubusercontent.com/shengqiangzhang/examples-of-web-crawlers/master/10.%E4%B8%80%E9%94%AE%E7%94%9F%E6%88%90%E4%B8%AA%E4%BA%BA%E5%BE%AE%E4%BF%A1%E6%9C%8B%E5%8F%8B%E5%9C%88%E6%95%B0%E6%8D%AE%E7%94%B5%E5%AD%90%E4%B9%A6/image/page2.png)]
紙質書效果
[外鏈圖片轉存失敗(img-eyiuaB4P-1566632687227)(https://raw.githubusercontent.com/shengqiangzhang/examples-of-web-crawlers/master/10.%E4%B8%80%E9%94%AE%E7%94%9F%E6%88%90%E4%B8%AA%E4%BA%BA%E5%BE%AE%E4%BF%A1%E6%9C%8B%E5%8F%8B%E5%9C%88%E6%95%B0%E6%8D%AE%E7%94%B5%E5%AD%90%E4%B9%A6/image/page3.jpeg)]
代碼思路
獲取微信書鏈接
看完效果圖之后,開始進入代碼編寫部分。首先,由于朋友圈數據的隱私性較高,手動獲取的話,需要使用root的安卓手機進行解密或對pc端備份的聊天記錄數據庫進行解密,這對大部分人來說難度較大。所以我們采取的思路是基于現有的數據進行打印電子書。
目前,已經有第三方服務支持導出朋友圈數據,微信公眾號【出書啦】就提供了這樣一種服務。這種服務很大可能性是基于安卓模擬器進行自動化采取操作的,具體就不詳細講了。
首先,關注該公眾號,然后開始制作微信書。該過程為小編添加你為好友,然后你將朋友圈開放給他看,等一會后采集完畢后,小編會發給你一個專屬鏈接,這個鏈接里面的內容就是你的個人朋友圈數據。
生成電子書
有了這個鏈接后,我們開始對該頁面的內容進行打印。
整個過程基于selenium自動化操作,如果你有了解過selenium的話,那么其實該過程是很簡單的。
首先,引導用戶輸入微信書鏈接,我們采用在瀏覽器彈出一個輸入文本框的形式讓用戶輸入數據。
首先,在selenium中執行js代碼,js代碼中完成彈出輸入文本框的功能。
輸入微信書鏈接
''' 遇到問題沒人解答?小編創建了一個Python學習交流QQ群:857662006 尋找有志同道合的小伙伴,互幫互助,群里還有不錯的視頻學習教程和PDF電子書! ''' # 以網頁輸入文本框形式提示用戶輸入url地址 def input_url():# js腳本random_id = [str(random.randint(0, 9)) for i in range(0,10)]random_id = "".join(random_id)random_id = 'id_input_target_url_' + random_idjs = """// 彈出文本輸入框,輸入微信書的完整鏈接地址target_url = prompt("請輸入微信書的完整鏈接地址","https://");// 動態創建一個input元素input_target_url = document.createElement("input");// 為其設置id,以便在程序中能夠獲取到它的值input_target_url.id = "id_input_target_url";// 插入到當前網頁中document.getElementsByTagName("body")[0].appendChild(input_target_url);// 設置不可見document.getElementById("id_input_target_url").style.display = 'none';// 設置value為target_url的值document.getElementById("id_input_target_url").value = target_url"""js = js.replace('id_input_target_url', random_id)# 執行以上js腳本driver.execute_script(js)上述js代碼的具體步驟為:彈出一個輸入文本框,創建一個動態元素,隨機命名該元素的id,并將這個動態元素插入到當前頁面中,使得可以在python中通過selenium獲取到輸入文本框的內容。
接著,在selenium中檢測是否存在該彈框,如果不存在則獲取該彈框的內容,并進行后續步驟,該過程代碼如下:
''' 遇到問題沒人解答?小編創建了一個Python學習交流QQ群:857662006 尋找有志同道合的小伙伴,互幫互助,群里還有不錯的視頻學習教程和PDF電子書! ''' # 執行以上js腳本 driver.execute_script(js) # 判斷彈出框是否存在 while(True):try:# 檢測是否存在彈出框alert = driver.switch_to.alerttime.sleep(0.5)except:# 如果拋異常,說明當前頁面不存在彈出框,即用戶點擊了取消或者確定break # 獲取用戶輸入的鏈接地址 target_url = WebDriverWait(driver, 20).until(EC.presence_of_element_located((By.ID, random_id))) value = target_url.get_attribute('value') # 刪除空格 value = value.strip()至此,value的值即為彈出框返回的內容。(你可能會問,直接另value=微信書鏈接不就可以了嗎?事實上確實可以 >*<|||,但是采用上述方式會有一個良好的交互效果,同時可以加深一下對selenium的了解程度*)
設置瀏覽器參數
當用戶輸入鏈接完畢后,開始對瀏覽器進行初始化設置。首先設置chromedriver路徑,可輸入絕對路徑或者相對路徑,./表示當前目錄下。不同系統和不同chrome版本需要下載不同的chromedriver,請下載合適自己的版本,chromedriver下載地址http://chromedriver.chromium.org/
接著,設置自動打印成pdf,這樣就可以默認打印成pdf了,省得我們手動打印,該步驟代碼如下:
''' 遇到問題沒人解答?小編創建了一個Python學習交流QQ群:857662006 尋找有志同道合的小伙伴,互幫互助,群里還有不錯的視頻學習教程和PDF電子書! ''' appState = {# 添加保存為pdf選項"recentDestinations": [{"id": "Save as PDF","origin": "local","account":""}],# 選擇保存為pdf選項"selectedDestinationId": "Save as PDF",# 版本2"version": 2,# 不顯示頁眉頁腳"isHeaderFooterEnabled": False }同時,設置自動打印模式,該步驟代碼如下:
profile = {# 打印前置參數'printing.print_preview_sticky_settings.appState': json.dumps(appState),# 默認下載、打印保存路徑'savefile.default_directory': os.getcwd() }通過這兩步,就實現了全自動打印效果。
分析網頁元素
接下來到了最關鍵的步驟,即分析網頁元素。這個步驟我們可以順便學習下基本的css,js知識。
首先,按F12打開網頁調試工具,對頁面上不必要的元素進行隱藏
[外鏈圖片轉存失敗(img-HIEEyyKZ-1566632687228)(https://raw.githubusercontent.com/shengqiangzhang/examples-of-web-crawlers/master/10.%E4%B8%80%E9%94%AE%E7%94%9F%E6%88%90%E4%B8%AA%E4%BA%BA%E5%BE%AE%E4%BF%A1%E6%9C%8B%E5%8F%8B%E5%9C%88%E6%95%B0%E6%8D%AE%E7%94%B5%E5%AD%90%E4%B9%A6/image/page4.png)]
我們可以看到,頂部的導航欄可能會影響打印效果,所以,我們將它隱藏。在調試工具中,選擇Copy Selector,得到返回的數據為body > header,通過selenium隱藏該元素的代碼如下:
# 隱藏導航欄,防止影響截圖效果 js = 'document.querySelector("body > header").style.display="none";' driver.execute_script(js)我們又發現,當前頁面顯示的數據只包含某個月朋友圈的數據,而不是所有朋友圈數據,那么如何顯示出所有朋友圈數據呢?通過分析可知,當點擊“下一月”按鈕后,會有新的元素顯示,而原來的元素被隱藏,而被隱藏的元素就是前面月份的數據。所以我們只要遍歷到最后一個月后,把前面所有元素顯示出來再打印就OK了。那么,如何判斷是最后一個月呢?我們通過分析又可知,當不是最后一個月時,“下一月”的class名為next-month,而當在最后一月時,“下一月”的class名為next-month disable,因此我們可以檢測它的class名進而知道是否處于最后一個月。該步驟代碼如下:
''' 遇到問題沒人解答?小編創建了一個Python學習交流QQ群:857662006 尋找有志同道合的小伙伴,互幫互助,群里還有不錯的視頻學習教程和PDF電子書! ''' # 判斷當下一月控件的class name 是否為next-month disable,如果是,則說明翻到最后一月了 page_source = driver.page_source# 每一個element代表每一頁,將每一頁中style的display屬性改成block,即可見狀態 for index, element in enumerate(element_left_list):# ..在xpath中表示上一級的元素,也就是父元素parent_element = element.find_element_by_xpath('..')# 獲取這個父元素的完整idparent_element_id = parent_element.get_attribute('id')# 將該父元素更改為可見狀態js = 'document.getElementById("{}").style.display="block";'.format(parent_element_id)driver.execute_script(js)但是,這樣會出現一個問題,即使我們成功打印了,但是我們不難保證頁面上的元素全部加載完成了,所以可能導致打印后某些元素沒有顯示出來,導致不是非常好看。因此,需要判斷何時加載結束。
[外鏈圖片轉存失敗(img-gi8vJWty-1566632687231)(https://raw.githubusercontent.com/shengqiangzhang/examples-of-web-crawlers/master/10.%E4%B8%80%E9%94%AE%E7%94%9F%E6%88%90%E4%B8%AA%E4%BA%BA%E5%BE%AE%E4%BF%A1%E6%9C%8B%E5%8F%8B%E5%9C%88%E6%95%B0%E6%8D%AE%E7%94%B5%E5%AD%90%E4%B9%A6/image/page5.png)]
通過分析我們得知,當網頁元素沒加載完畢時,會有一個“loading”提示,當網頁元素加載完畢后,該元素隱藏起來了。因此,我們可以判斷該元素是否隱藏來得知當前頁面元素是否加載完畢。該部分代碼如下:
# 等待當前頁面所有數據加載完畢,正常情況下數據加載完畢后,這個‘加載中’元素會隱藏起來 while (True):loading_status = WebDriverWait(driver, 20).until(EC.presence_of_element_located((By.CSS_SELECTOR, 'div.j-save-popup.save-popup')))if (loading_status.is_displayed() == False):break可是,我們又發現,及時等待網頁元素加載完畢了,還是有部分圖片沒有顯示出來。
[外鏈圖片轉存失敗(img-aj7nf5ck-1566632687234)(https://raw.githubusercontent.com/shengqiangzhang/examples-of-web-crawlers/master/10.%E4%B8%80%E9%94%AE%E7%94%9F%E6%88%90%E4%B8%AA%E4%BA%BA%E5%BE%AE%E4%BF%A1%E6%9C%8B%E5%8F%8B%E5%9C%88%E6%95%B0%E6%8D%AE%E7%94%B5%E5%AD%90%E4%B9%A6/image/page6.png)]
這就納悶了,是為什么呢?通過分析我們又得知,這些圖片處于加載狀態的時候,class名為lazy-img,通過字面意思,我們大概可以猜得出它是懶加載的意思,也就是用戶滑動頁面到那里時才進行加載,以便節省服務器壓力。
所以我們可以通過滑動到每一個class名為lazy-img的元素,使得它進行加載。那么?一個合適的方法就是,通過js定位到該元素,直到所有class名為lazy-img的元素不存在。
while(True):try:lazy_img = driver.find_elements_by_css_selector('img.lazy-img')js = 'document.getElementsByClassName("lazy-img")[0].scrollIntoView();'driver.execute_script(js)time.sleep(3)except:# 找不到控件img.lazy-img,所以退出循環break其中,document.getElementsByClassName("lazy-img")[0]指的是document.getElementsByClassName("lazy-img")的第一個元素,scrollIntoView()指的是滾動到該元素的位置
打印電子書
通過上述步驟,我們已經成功地隱藏部分可能會影響外觀的元素,同時也顯示所有所需的元素,接下來,就差打印部分了。可以直接通過js代碼喚起瀏覽器打印功能,并且,之前我們已經設置為自動打印pdf格式了,所以它將自動打印為pdf。但是,打印到哪里呢?這里需要設置下瀏覽器默認存儲位置,保存的位置為當前目錄。該步驟代碼如下:
# 默認下載、打印保存路徑 'savefile.default_directory': os.getcwd()# 調用chrome打印功能 driver.execute_script('window.print();')打印完成后,設置退出瀏覽器driver.quit()
經過測試,該電子書為超清版本,大小約16MB,所以質量還算不錯的。
如何運行
# 跳轉到當前目錄 cd 目錄名 # 先卸載依賴庫 pip uninstall -y -r requirement.txt # 再重新安裝依賴庫 pip install -r requirement.txt # 開始運行 python main.py總結
以上是生活随笔為你收集整理的用Python 给你的个人微信朋友圈数据生成一本电子书吧!的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 用 Python 一键分析你的上网行为,
- 下一篇: 不用第三方库,也能用 Python 作图