一、为什么要搞
工作中,会在工作电脑上的Chrome、Edge、Firefox浏览器中保存大量的书签。那么问题来了,比如Chrome浏览器并未登录账号,书签只保存在本地,当不在公司时就比较难搞了,拿不到链接还搞个毛线啊。
所以在平常工作都会抽空将Chrome、Edge浏览器中的书签导出,再导入到Firefox的书签中(Firefox浏览器登录了账号)。可这不就是重复性的工作吗?
二、准备如何搞
原本有个方案是使用Python的selenium库操作浏览器实现书签自动导出导入,可是这个方案会存在以下的问题:
1.各浏览器版本会不定时更新,Python脚本中的浏览器driver驱动也需要相应地更新
2.selenium操作浏览器需要对页面的各种元素定位并发送相应的指令,要对三种浏览器分别调试,费时费力
3.操作浏览器时,很可能会有一些随机弹窗出现,这使得不确定性提高,从而降低脚本的稳定性
于是乎,方案变更为:使用Python自动导出浏览器的书签并发送至邮箱
那么先来做好准备工作:
1.找到各浏览器的书签保存位置
Chrome和Edge的书签保存在本地的Bookmarks中,是个JSON文件
我本机的Chrome和Edge书签路径如下:
bookmarks_path_chrome = r'C:\Users\Administrator\AppData\Local\Google\Chrome\User Data\Default'
bookmarks_path_edge = r'C:\Users\Administrator\AppData\Local\Microsoft\Edge\User Data\Default'
Firefox的书签保存在places.sqlite中,是个sqlite数据库
我本机的Firefox书签路径如下:
bookmarks_path_firefox = r'C:\Users\Administrator\AppData\Roaming\Mozilla\Firefox\Profiles\iw3bxbjx.default-1659145063858'
2.准备要使用到的Python第三方库
导出的书签文件保存为excel文件,使用tablib库
发送邮件使用zmail库
pip install tablib
pip install zmail
3.开启邮箱的POP3/SMTP服务并获取授权码
设置后才能正常在授权设备上登录邮箱
我的163邮箱设置如下图所示,不同邮箱设置界面会有差异
三、说搞咱就搞
Edge、Chrome书签导出
Chrome和Edge的书签存储方式类似,只需要读取Bookmarks文件即可
下面以Edge浏览器为例:
import os.path
class EdgeChromeExtract:
"""
导出Edge和Chrome浏览器的书签
"""
def __init__(self, bookmarks_path):
self.file_path = bookmarks_path + os.sep + 'Bookmarks'
def read(self):
"""
读取书签文件
"""
if os.path.exists(self.file_path):
with open(self.file_path, 'r+', encoding='utf-8') as f:
return f.read()
if __name__ == "__main__":
bookmarks_path_edge = r'C:\Users\Administrator\AppData\Local\Microsoft\Edge\User Data\Default'
bm_e = EdgeChromeExtract(bookmarks_path_edge)
print(bm_e.read())
运行结果:
倒是读取成功了,会发现书签名name中包含了“+x,”等不可打印字符,不可忍受,得处理一下
在EdgeChromeExtract类中添加一个to_json方法:
def to_json(self):
def gen():
for s in self.read():
if s.isprintable():
yield s
return json.loads(''.join(gen()))
print(bm_e.to_json())
运行结果:
简化一下,在read方法中操作一手可得到相同结果
def read(self):
"""
读取书签文件
"""
if os.path.exists(self.file_path):
with open(self.file_path, 'r+', encoding='utf-8') as f:
# return f.read()
return json.loads(''.join(s for s in f.read() if s.isprintable()))
接下来就是解析json,提取出书签名称和链接
def extract(self):
"""
导出书签名称和地址
"""
json_data = self.read()
results_list = []
for t in ['bookmark_bar', 'other']:
for i in json_data['roots'][t]['children']:
if 'children' in i.keys(): # 包含children
for j in i['children']:
results_list.append({'name': j['name'], 'url': j['url']})
else: # 不包含children
results_list.append({'name': i['name'], 'url': i['url']})
return results_list
if __name__ == "__main__":
bookmarks_path_edge = r'C:\Users\Administrator\AppData\Local\Microsoft\Edge\User Data\Default'
bm_e = EdgeChromeExtract(bookmarks_path_edge)
print(bm_e.extract())
运行结果:
为了适配Chrome书签的JSON格式,添加了一个递归处理JSON的方法
def recursion_json(self, data):
"""
递归处理json提取书签名和地址
"""
results = []
for i in data:
if 'name' in i and 'url' in i: # 若name和url键均存在则提取
results.append({'name': i['name'], 'url': i['url']})
if 'children' in i: # 如果children键存在则递归
results.extend(self.recursion_json(i['children'])) # 使用extend函数扩展结果列表
return results
在extract方法中调用
def extract(self):
"""
导出书签名称和地址
"""
json_data = self.read()
results_list = []
for t in ['bookmark_bar', 'other']:
# for i in json_data['roots'][t]['children']:
# if 'children' in i.keys(): # 包含children
# for j in i['children']:
# results_list.append({'name': j['name'], 'url': j['url']})
# else: # 不包含children
# results_list.append({'name': i['name'], 'url': i['url']})
results_list.extend(self.recursion_json(json_data['roots'][t]['children']))
return results_list
来试下导出Chrome的书签
if __name__ == "__main__":
bookmarks_path_chrome = r'C:\Users\Administrator\AppData\Local\Google\Chrome\User Data\Default'
bm_c = EdgeChromeExtract(bookmarks_path_chrome).extract()
print(bm_c)
运行结果:
Firefox书签导出
先看看sqlite数据库的结构,书签的名称和链接分别放在moz_bookmarks和moz_places两个表中
编写好查询SQL,来连接数据库获取查询结果
import os.path
import sqlite3
import traceback
class FirefoxExtract:
"""
导出Firefox浏览器的书签
"""
def __init__(self, bookmarks_path):
self.file_path = bookmarks_path + os.sep + 'places.sqlite'
self.conn = sqlite3.connect(self.file_path) # 连接数据库
self.cur = self.conn.cursor() # 数据库游标
def extract(self,
sql="select b1.title,p.url from moz_bookmarks b1 left join moz_places p on b1.fk=p.id left join "
"moz_bookmarks b2 on b1.parent=b2.id where b1.type=1 and b2.type=2 and b2.title !='Mozilla "
"Firefox' order by b2.title,b1.position desc;"):
try:
self.cur.execute(sql) # 执行查询sql
results = self.cur.fetchall() # 获取查询结果
return results
except Exception as err:
info = f"出了点小问题!\n{repr(err)}\n{traceback.format_exc()}"
print(info)
self.conn.rollback() # 回滚
finally:
self.conn.close() # 关闭连接
if __name__ == "__main__":
bookmarks_path_firefox = r'C:\Users\Administrator\AppData\Roaming\Mozilla\Firefox\Profiles\iw3bxbjx.default-1659145063858'
bm_f = FirefoxExtract(bookmarks_path_firefox).extract()
print(bm_f)
运行结果:
啊!结果又包含了这种不可打印字符,还要处理一手
优化一下获取的查询结果
self.cur.execute(sql) # 执行查询sql
results = self.cur.fetchall() # 获取查询结果
# return results
results_list = [{'name': ''.join(j for j in i[0] if j[0].isprintable()), 'url': i[1]} for i in results]
return results_list
运行结果:
书签保存为excel
使用tablib库,将导出的书签保存为bookmarks.xlsx
import tablib
def bookmarks_2_excel(bookmarks, file_name='bookmarks.xlsx'):
"""
书签导出为excel
"""
data = tablib.Dataset() # 创建tablib数据集
data.headers = ['名称', '地址'] # 表头
for bm in bookmarks: # 添加行数据
data.append([bm['name'], bm['url']])
with open(file_name, 'wb') as f: # 导出为excel
f.write(data.export('xlsx'))
if __name__ == "__main__":
bookmarks_path_chrome = r'C:\Users\Administrator\AppData\Local\Google\Chrome\User Data\Default'
bookmarks_path_edge = r'C:\Users\Administrator\AppData\Local\Microsoft\Edge\User Data\Default'
bookmarks_path_firefox = r'C:\Users\Administrator\AppData\Roaming\Mozilla\Firefox\Profiles\iw3bxbjx.default-1659145063858'
bm_e = EdgeChromeExtract(bookmarks_path_edge).extract()
bm_c = EdgeChromeExtract(bookmarks_path_chrome).extract()
bm_f = FirefoxExtract(bookmarks_path_firefox).extract()
bookmarks_list = bm_e + bm_c + bm_f
bookmarks_2_excel(bookmarks_list)
运行结果:
发送书签excel邮件
通过zmail建立邮箱连接,构造邮件内容,发送邮件
import datetime
import os.path
import traceback
import zmail
def send_email(file_name='bookmarks.xlsx', sender='xxxx@163.com', receiver='xxxx@163.com'):
"""
书签excel发送到邮箱
"""
try:
file_path = os.path.dirname(os.path.abspath(__file__)) + os.sep + file_name # 书签文件路径
rq = datetime.date.today() # 今天的日期
server = zmail.server(sender, 'L***************V') # 发件人邮箱地址和授权码
sign = '\n\n\n--\nDriver_Won\n1*********4\nHave a nice day (^_^)' # 邮件签名
mail_content = {
'from': f'Driver_Won<{sender}>', # 发件人及昵称
'subject': f'书签汇总{rq}', # 主题
'content_text': '本邮件由系统自动发出,无需回复!' + sign, # 文本内容
'attachments': file_path # 文件附件
}
server.send_mail(receiver, mail_content) # 收件人地址和邮件内容
except Exception as e:
info = f"邮件发送失败!\n{repr(e)}\n{traceback.format_exc()}"
print(info)
else:
print('邮件发送成功!')
if __name__ == "__main__":
send_email()
运行结果:
四、搞完就收工
本机是windows电脑,将Python脚本添加到windows的计划任务中,定时自动执行
有效代替了手动导入导出书签的工作,随时随地手机上也能查看到保存在各浏览器上的书签了