用Python下载Lofter上“喜欢”的文章和图片

本文介绍如何使用Python通过selenium下载Lofter上标记为‘喜欢’的文章和图片。内容包括步骤指导、可能出现的问题及解决方案,以及未来可能的改进方向。
Python3.8

Python 是一种高级、解释型、通用的编程语言,以其简洁易读的语法而闻名,适用于广泛的应用,包括Web开发、数据分析、人工智能和自动化脚本

# 所有文字+【文中外链地址】保存为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()

您可能感兴趣的与本文相关的镜像

Python3.8

Python3.8

Conda
Python

Python 是一种高级、解释型、通用的编程语言,以其简洁易读的语法而闻名,适用于广泛的应用,包括Web开发、数据分析、人工智能和自动化脚本

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值