抓取网页生成电子书(微信公众号【出书啦】效果纸质书效果代码思路获取)
优采云 发布时间: 2022-03-01 11:23抓取网页生成电子书(微信公众号【出书啦】效果纸质书效果代码思路获取)
[目录]
为您的个人微信朋友圈数据生成电子书!介绍
朋友圈留着你的数据,留着美好的回忆,记录着我们的每一点成长。从某种意义上说,发朋友圈就是记录生活,感受生活,见证每个人每一步的成长。
如此珍贵的记忆,何不保存呢?只需一杯咖啡时间,即可一键打印朋友圈。可以是纸质书也可以是电子书,可以长期保存,比拍照好,有时间足迹记忆。
现在,您可以选择打印电子书或纸质书。如果印刷纸质书,可以找第三方机构购买;如果你打印一本电子书,我们可以自己生成,这样可以节省很多钱。
部分截图
在开始编写代码思路之前,我们先来看看最终生成的效果。
电子书效果
纸书效果
获取微信书籍链接的代码思路
看完效果图,开始进入代码编写部分。首先,由于朋友圈数据的隐私性较高,如果手动获取,需要使用root安卓手机解密或解密PC机备份的聊天记录数据库,很难大多数人。所以我们的想法是根据现有数据打印电子书。
目前已经有第三方服务支持导出朋友圈数据,微信公众号【出版图书】提供了这样的服务。这种服务很有可能是基于安卓模拟器自动化的,我就不赘述了。
先关注公众号,然后开始制作微信书籍。这个过程将你添加为编辑的朋友,然后你向他打开朋友圈。过一会采集,小编会给你发一个专属链接,这个链接里的内容就是你的Personal Moments。
生成电子书
有了这个链接,我们开始打印页面的内容。
整个过程基于 selenium 自动化。如果你知道 selenium,那么这个过程其实很简单。
首先,为了引导用户输入微信图书链接,我们采用在浏览器中弹出输入文本框的形式,让用户输入数据。
首先在selenium中执行js代码,完成js代码中弹出输入文本框的功能。
进入微信图书链接
# 以网页输入文本框形式提示用户输入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_id
js = """
// 弹出文本输入框,输入微信书的完整链接地址
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 中。如果不存在,则获取弹框的内容并执行下一步。流程代码如下:
# 执行以上js脚本
driver.execute_script(js)
# 判断弹出框是否存在
while(True):
try:
# 检测是否存在弹出框
alert = driver.switch_to.alert
time.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=微信书链接可以吗?其实>_header确实是可以的,通过selenium隐藏这个元素的代码如下:
# 隐藏导航栏,防止影响截图效果
js = 'document.querySelector("body > header").style.display="none";'
driver.execute_script(js)
我们也发现当前页面显示的数据只收录某月的朋友圈数据,而不是所有的朋友圈数据,那么如何显示所有的朋友圈数据呢?通过分析可以看出,当点击“下个月”按钮时,会显示一个新的元素,而原来的元素会被隐藏,隐藏的元素就是上个月的数据。所以我们只需要遍历到上个月,显示之前的所有元素,然后打印出来。那么,如何判断是上个月呢?我们也可以通过分析得知,当不是上个月时,“下个月”的类名是下个月,当是上个月时,“下个月”的类名是下个月禁用,所以我们可以检测它的类名,就知道是不是在上个月了。
# 判断当下一月控件的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('..')
# 获取这个父元素的完整id
parent_element_id = parent_element.get_attribute('id')
# 将该父元素更改为可见状态
js = 'document.getElementById("{}").style.display="block";'.format(parent_element_id)
driver.execute_script(js)
但是,这种方式会出现问题。即使我们打印成功,我们也不难保证页面上的所有元素都加载完毕,所以有些元素打印后可能无法显示,导致不太好看。因此,需要判断加载何时结束。
通过分析我们知道,网页元素未加载时,会出现“加载中”的提示,而网页元素加载时,该元素是隐藏的。因此,我们可以通过判断元素是否隐藏来知道当前页面元素是否被加载。这部分代码如下:
# 等待当前页面所有数据加载完毕,正常情况下数据加载完毕后,这个‘加载中’元素会隐藏起来
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
但是我们也发现,在等待页面元素及时加载后,还是有一些图片没有显示出来。
这很令人困惑,为什么?通过分析我们还了解到,当这些图片处于加载状态时,类名是lazy-img。从字面意思上,我们大概可以猜到它的意思是延迟加载,也就是用户在那里滑动页面,直到加载完毕。,以节省服务器压力。
所以我们可以通过一个名为lazy-img的类滑动到每个元素来加载它。所以?一个合适的方法是通过js定位元素,直到所有类名为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
补充
完整版源码存放在github上,需要的可以下载
项目持续更新中,欢迎您star此项目