# 所有文字+【文中外链地址】保存为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 random
class 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, title
def 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:
pass
for 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:
pass
try:
self.downloadpicintext(i, j, html, title) # 下载文字中的图片
except:
pass
self.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))
break
elif i == self.pageleap - 1:
# 下一页
try:
self.tiaozhuan()
except:
print('第{}页跳转失败'.format(i))
break
elif 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))
break
elif 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))
break
elif 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))
break
elif 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))
break
elif 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))
break
elif i == self.pageleap - 1:
# 下一页
try:
self.tiaozhuan()
except:
print('第{}页跳转失败'.format(i))
break
elif 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))
break
elif 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))
break
elif self.pageleap == self.endpage:
for i in range(1, self.endpage + 1): # 页面大循环
if i < self.endpage:
# 下一页
try:
self.zhijietiaozhuan()
except:
print('第{}页跳转失败'.format(i))
break
elif 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))
break
def main(self):
self.get_driver()
self.log_in_by_tel()
self.xihuan()
self.loop()
if __name__ == '__main__':
lofter = Lofter()
lofter.main()
本文介绍如何使用Python通过selenium下载Lofter上标记为‘喜欢’的文章和图片。内容包括步骤指导、可能出现的问题及解决方案,以及未来可能的改进方向。

194

被折叠的 条评论
为什么被折叠?



