用Python下载Lofter上“喜欢”的文章和图片
# 所有文字+【文中外鏈地址】保存為txt,命名規則:頁數_該頁第幾篇 標題.txt
# 有圖片的自動下載,沒有圖片的就不下載,命名規則:頁數_該頁第幾篇 標題_圖片序號(從1開始).后綴
# 這里暫時只有手機登錄方式,其他登錄方式都很簡單,可以自己探索
# selenium用到chromedriver:
? ? ? ? ? Step1:下載chrome瀏覽器并查看chrome版本
? ? ? ? ? Step2:http://chromedriver.storage.googleapis.com/index.html下載對應版本的chromedriver(沒有一樣版本的下載附近版本的就可以)
? ? ? ? ? Step3:將chromedriver與本代碼放在同一個文件夾中!!!(或者改一下路徑代碼)
# 如果你熟練使用python,可以跳過以下保姆級啰嗦:
? ? ? ? ? 1. 記得先下載代碼用到的庫
? ? ? ? ? 2. 輸入手機號、密碼和保存路徑的那里,可以自行將input改為固定字符串(正確舉例:'13900000000',必須帶英文引號),路徑最后一定要帶上'/',而且帶'\'的話可能會出問題(正確舉例:'D:\Lofter/')
? ? ? ? ? 3. 存在圖片下載失敗的情況會進行提示“5_62_1.png未能保存”并繼續運行程序,這種情況下推薦手動去網頁里保存一下圖片(例如5_62_1.png是第5頁第62篇,可以根據已成功保存的5_62 blablabla.txt查看這篇的文字內容,然后在網頁上ctrl+F進行查找),失敗概率大概是10頁(約1000篇圖文)里面可能會有5~8張圖片無法保存。
? ? ? ? ? 4. 存在不明原因中斷的情況,會提示“第x頁第x篇完蛋 or 第x頁完”+“完蛋 or 全部結束”,或僅提示“第x頁第x篇完蛋 or 第x頁完”就跳轉至下一頁。這種情況下可重新從第x頁第x篇開始下載。
? ? ? ? ? 5.?chromedriver不要改名!!就叫chromedriver(或者改代碼也行)
# 可能會后續更新的點(歡迎繼續提出建議):
? ? ? ? ? 1. 本來想把文章在Lofter上的tag也寫進txt里,后面感覺個人不太需要就沒有寫了
? ? ? ? ? 2. 在評論里的外鏈沒有寫進txt,有時間會試著寫一下
? ? ? ? ? 3. 有可能的話想把外鏈里的圖文也保存下來,工程量比較大,想寫的時候再寫
? ? ? ? ? 4. 如果有bug、建議、疑問,歡迎討論,虛心接受一切與代碼有關和無關的批評建議!!
# !!!寫手畫手創作不易,請務必尊重版權!!!代碼僅作為練習Python或收藏喜歡的圖文使用
#?2021/08/08 12:40更新內容:這次的更新包括重新定位、標題存儲的修改、循環的精簡,以及重點針對網頁本身的跳轉bug進行了相應調整,應該算是短期內較為完整的一版了。
# 以上說明的最后更新時間:2021/08/08 12:40;代碼的最后更新時間:2021/08/10 11:46
import os import time from selenium import webdriver from bs4 import BeautifulSoup import urllib.request import randomclass Lofter:def __init__(self):self.pageleap = int(input('要從第幾頁開始下載'))self.articleleap = int(input('要從第{}頁的第幾篇開始下載'.format(self.pageleap)))self.endpage = int(input('一共有多少頁?'.format(self.pageleap)))self.username = input('請輸入手機號')self.password = input('請輸入密碼')self.savepathf = input('請輸入保存地址')def get_driver(self):exe_path = os.path.join(os.path.split(__file__)[0], 'chromedriver.exe')chrome_options = webdriver.ChromeOptions()chrome_options.add_argument('--headless') # 增加無界面選項chrome_options.add_argument('--disable-gpu') # 如果不加這個選項,有時定位會出現問題self.driver = webdriver.Chrome(executable_path=exe_path, options=chrome_options) # 聲明瀏覽器url = 'http://www.lofter.com/'self.driver.get(url) # 打開瀏覽器預設網址self.driver.implicitly_wait(30) # 隱式等待time.sleep(3)def log_in_by_tel(self):ele_login = self.driver.find_element_by_xpath('/html/body/div[1]/div/div[2]/div[2]/div/div/div[1]/div/a[2]') # 定位手機號密碼登錄ele_login.click() # 點擊time.sleep(1) # 等待ele_tel = self.driver.find_element_by_xpath('/html/body/div[1]/div/div[2]/div[2]/div/div/div[2]/div[2]/form/div[1]/div[1]/input') # 定位填寫手機號碼的方格ele_tel.send_keys(self.username) # 自動輸入電話號碼time.sleep(1) # 等待ele_pin = self.driver.find_element_by_xpath('/html/body/div[1]/div/div[2]/div[2]/div/div/div[2]/div[2]/form/div[1]/div[2]/input') # 定位填寫密碼的方格ele_pin.send_keys(self.password) # 自動輸入密碼time.sleep(1) # 等待ele_yes = self.driver.find_element_by_xpath('/html/body/div[1]/div/div[2]/div[2]/div/div/div[2]/div[2]/form/div[1]/div[3]/span[1]/label') # 定位同意協議勾選ele_yes.click() # 點擊勾選time.sleep(1) # 等待ele_log = self.driver.find_element_by_xpath('/html/body/div[1]/div/div[2]/div[2]/div/div/div[2]/div[2]/form/div[1]/button') # 定位登錄按鈕ele_log.click() # 點擊self.driver.implicitly_wait(30) # 隱式等待time.sleep(3) # 等待def xihuan(self):ele_xihuan = self.driver.find_element_by_xpath('/html/body/div[4]/div/div[2]/div[1]/div/div[2]/div/div/div[2]/div[3]/div[6]/a') # 定位“我的喜歡”ele_xihuan.click() # 點擊self.driver.implicitly_wait(30) # 隱式等待time.sleep(3) # 等待for p in range(1, 7):self.downward() # 頁面下拉self.driver.execute_script("window.scrollTo(0,0);") # 上拉至頂部def downward(self):self.driver.execute_script("window.scrollTo(0, document.body.scrollHeight);") # 下拉至底部self.driver.implicitly_wait(30)time.sleep(2)def findarticle(self, article):ele_page = self.driver.find_element_by_xpath('/html/body/div[4]/div/div[1]/div[{}]/div[3]/div/div[1]/a'.format(article + 4)) # 定位文章右上角ele_page.click() # 點擊self.driver.implicitly_wait(30)time.sleep(3)windows = self.driver.window_handles # 獲取打開的多個窗口句柄self.driver.switch_to.window(windows[-1]) # 切換到當前最新打開的窗口self.driver.implicitly_wait(30)html = BeautifulSoup(self.driver.page_source, 'html.parser') # 獲取頁面title = html.title.get_text() # 獲取標題return html, titledef downloadtext(self, page, article, html, title):try:text = html.find_all(class_='text')[1].get_text() # 尋找文字outurl1 = ''outurlli = html.find_all(class_='text')[1].find_all('a') # 尋找外鏈outurllilen = len(outurlli) # 計算外鏈個數for u in range(1, outurllilen + 1):outurl1 = outurl1 + '\n' + outurlli[u - 1]['href'] # 外鏈合并except:try:text = html.find_all(class_='text')[0].get_text() # 尋找文字outurl1 = ''outurlli = html.find_all(class_='text')[0].find_all('a') # 尋找外鏈outurllilen = len(outurlli) # 計算外鏈個數for u in range(1, outurllilen + 1):outurl1 = outurl1 + '\n' + outurlli[u - 1]['href'] # 外鏈合并except:text = ''outurl1 = ''try:txtcont = html.find_all(class_='txtcont')[0].get_text() # 尋找文字outurl2 = ''outurlli = html.find_all(class_='txtcont')[0].find_all('a') # 尋找外鏈outurllilen = len(outurlli) # 計算外鏈個數for u in range(1, outurllilen + 1):outurl2 = outurl2 + '\n' + outurlli[u - 1]['href'] # 外鏈合并except:txtcont = ''outurl2 = ''content = title + '\n' * 2 + text + '\n' * 2 + txtcont + '\n' * 2 + outurl1 + '\n' * 2 + outurl2 # 文檔內容編輯title = title.replace("*", " ").replace("?", " ").replace("|", " ") # 標題修改title = title.replace("<", " ").replace(">", " ").replace(":", " ") # 標題修改title = title.replace("/", " ").replace("\n", " ").replace('"', " ") # 標題修改try:savepath = self.savepathf + '{}_{} {}.txt'.format(page, article, title) # 存儲地址with open(savepath, 'w', encoding='utf-8') as fb:fb.write(content) # 寫入except:savepath = self.savepathf + '{}_{}.txt'.format(page, article) # 存儲地址with open(savepath, 'w', encoding='utf-8') as fb:fb.write(content) # 寫入time.sleep(2)def downloadimgclasstag(self, page, article, html, title):allpic = html.find_all(class_="imgclasstag") # 尋找圖片allpiclen = len(allpic) # 計算圖片個數for pic in range(1, allpiclen + 1):url = allpic[pic - 1].img['src'] # 圖片鏈接suff = os.path.splitext(url)[1].split('?')[0] # 圖片后綴title = title.replace("*", " ").replace("?", " ").replace("|", " ")title = title.replace("<", " ").replace(">", " ").replace(":", " ")title = title.replace("/", " ").replace("\n", " ").replace('"', " ") # 標題修改try:picpath = self.savepathf + '{}_{} {}_{}{}'.format(page, article, title, pic, suff)time.sleep(random.randint(1, 3))urllib.request.urlretrieve(url, picpath) # 下載except:try:picpath = self.savepathf + '{}_{}_{}{}'.format(page, article, pic, suff)time.sleep(random.randint(1, 3))urllib.request.urlretrieve(url, picpath)except:print('{}_{}_{}{}未能保存'.format(page, article, pic, suff)) # 失敗提示def downloadpicintext(self, page, article, html, title):try:text = html.find_all(class_='text')[1]allpic = text.find_all('img')allpiclen = len(allpic)except:try:text = html.find_all(class_='text')[0]allpic = text.find_all('img')allpiclen = len(allpic)except:try:txtcont = html.find_all(class_='txtcont')[0]allpic = text.find_all('img')allpiclen = len(allpic)except:passfor pic in range(1, allpiclen + 1):url = allpic[pic - 1]['src']suff = os.path.splitext(url)[1].split('?')[0]title = title.replace("*", " ").replace("?", " ").replace("|", " ")title = title.replace("<", " ").replace(">", " ").replace(":", " ")title = title.replace("/", " ").replace("\n", " ").replace('"', " ") # 標題修改try:picpath = self.savepathf + '{}_{} {}_t{}{}'.format(page, article, title, pic, suff)time.sleep(random.randint(1, 3))urllib.request.urlretrieve(url, picpath)except:try:picpath = self.savepathf + '{}_{}_{}{}'.format(page, article, pic, suff)time.sleep(random.randint(1, 3))urllib.request.urlretrieve(url, picpath)except:print('{}_{}_{}{}未能保存'.format(page, article, pic, suff))def closearticle(self):# 關閉單篇文章self.driver.close() # 關閉當前頁面time.sleep(1)windows = self.driver.window_handles # 獲取打開的多個窗口句柄self.driver.switch_to.window(windows[0]) # 切換到當前最新打開的窗口def save(self, i, j):html, title = self.findarticle(j) # 尋找文章self.downloadtext(i, j, html, title) # 下載文字try:self.downloadimgclasstag(i, j, html, title) # 下載圖片except:passtry:self.downloadpicintext(i, j, html, title) # 下載文字中的圖片except:passself.closearticle() # 關閉當前文章def zhijietiaozhuan(self):ele_next_page = self.driver.find_element_by_css_selector('[class="next iblock"]') # 跳轉下一頁ele_next_page.click()self.driver.implicitly_wait(30)time.sleep(3)for p in range(1, 7):self.downward()def tiaozhuan(self):ele_next_page = self.driver.find_element_by_css_selector('[class="next iblock"]') # 跳轉下一頁ele_next_page.click()self.driver.implicitly_wait(30)time.sleep(3)for p in range(1, 7):self.downward()ele_next_page = self.driver.find_element_by_css_selector('[class="next iblock"]') # 跳轉下下頁ele_next_page.click()self.driver.implicitly_wait(30)time.sleep(3)for p in range(1, 7):self.downward()ele_next_page = self.driver.find_element_by_css_selector('[class="prev iblock"]') # 跳轉上一頁ele_next_page.click()self.driver.implicitly_wait(30)time.sleep(1)def loop(self):if self.pageleap < self.endpage - 1:for i in range(1, self.endpage + 1): # 頁面大循環if i < self.pageleap - 1:# 下一頁try:self.zhijietiaozhuan()except:print('第{}頁跳轉失敗'.format(i))breakelif i == self.pageleap - 1:# 下一頁try:self.tiaozhuan()except:print('第{}頁跳轉失敗'.format(i))breakelif i == self.pageleap:self.driver.execute_script("window.scrollTo(0,0);") # 上拉至頂部for j in range(self.articleleap, 150): # 單篇小循環try:self.save(i, j)except:print('第{}頁第{}篇完蛋 or 第{}頁完'.format(i, j, i))break# 下一頁try:self.tiaozhuan()except:print('第{}頁跳轉失敗'.format(i))breakelif i > self.pageleap and i < self.endpage - 1:self.driver.execute_script("window.scrollTo(0,0);") # 上拉至頂部for j in range(1, 150): # 單篇小循環try:self.save(i, j)except:print('第{}頁第{}篇完蛋 or 第{}頁完'.format(i, j, i))break# 下一頁try:self.tiaozhuan()except:print('第{}頁跳轉失敗'.format(i))breakelif i == self.endpage - 1:self.driver.execute_script("window.scrollTo(0,0);") # 上拉至頂部for j in range(1, 150): # 單篇小循環try:self.save(i, j)except:print('第{}頁第{}篇完蛋 or 第{}頁完'.format(i, j, i))break# 下一頁try:self.zhijietiaozhuan()except:print('第{}頁跳轉失敗'.format(i))breakelif i == self.endpage:self.driver.execute_script("window.scrollTo(0,0);") # 上拉至頂部for j in range(1, 150): # 單篇小循環try:self.save(i, j)except:print('第{}頁第{}篇完蛋 or 全部結束'.format(i, j))breakelif self.pageleap == self.endpage - 1:for i in range(1, self.endpage + 1): # 頁面大循環if i < self.pageleap - 1:# 下一頁try:self.zhijietiaozhuan()except:print('第{}頁跳轉失敗'.format(i))breakelif i == self.pageleap - 1:# 下一頁try:self.tiaozhuan()except:print('第{}頁跳轉失敗'.format(i))breakelif i == self.pageleap:self.driver.execute_script("window.scrollTo(0,0);") # 上拉至頂部for j in range(self.articleleap, 150): # 單篇小循環try:self.save(i, j)except:print('第{}頁第{}篇完蛋 or 第{}頁完'.format(i, j, i))break# 下一頁try:self.zhijietiaozhuan()except:print('第{}頁跳轉失敗'.format(i))breakelif i == self.endpage:self.driver.execute_script("window.scrollTo(0,0);") # 上拉至頂部for j in range(1, 150): # 單篇小循環try:self.save(i, j)except:print('第{}頁第{}篇完蛋 or 全部結束'.format(i, j))breakelif self.pageleap == self.endpage:for i in range(1, self.endpage + 1): # 頁面大循環if i < self.endpage:# 下一頁try:self.zhijietiaozhuan()except:print('第{}頁跳轉失敗'.format(i))breakelif i == self.endpage:self.driver.execute_script("window.scrollTo(0,0);") # 上拉至頂部for j in range(self.articleleap, 150): # 單篇小循環try:self.save(i, j)except:print('第{}頁第{}篇完蛋 or 全部結束'.format(i, j))breakdef main(self):self.get_driver()self.log_in_by_tel()self.xihuan()self.loop()if __name__ == '__main__':lofter = Lofter()lofter.main()總結
以上是生活随笔為你收集整理的用Python下载Lofter上“喜欢”的文章和图片的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Fabric中的私有数据
- 下一篇: Python3:私有成员