id: 9054f7808c5a4fc6bd0efe55f69b775e
parent_id: 
item_type: 1
item_id: 9b6f56e48e684ee89bd5eb1a9ec1c2e9
item_updated_time: 1764365022239
title_diff: "[{\"diffs\":[[1,\"抓取网页内容生成Kindle电子书\"]],\"start1\":0,\"start2\":0,\"length1\":0,\"length2\":17}]"
body_diff: "[{\"diffs\":[[1,\"<html>\\\r\\\n<head>\\\r\\\n  <title>抓取网页内容生成Kindle电子书</title>\\\r\\\n  <basefont face=\\\"微软雅黑\\\" size=\\\"2\\\" />\\\r\\\n  <meta http-equiv=\\\"Content-Type\\\" content=\\\"text/html;charset=utf-8\\\" />\\\r\\\n  <meta name=\\\"exporter-version\\\" content=\\\"YXBJ Windows/608924 (zh-CN, DDL); Windows/10.0.0 (Win64); EDAMVersion=V2;\\\"/>\\\r\\\n  <meta name=\\\"application-data:2525275\\\" content=\\\"6692893/s30/ef2077b5-8d18-4193-959d-c123d2991f64/app.yinxiang.com\\\"/>\\\r\\\n  <style>\\\r\\\n\\tbody, td {\\\r\\\n\\t  font-family: 微软雅黑;\\\r\\\n\\t  font-size: 12pt;\\\r\\\n\\t}\\\r\\\n  </style>\\\r\\\n</head>\\\r\\\n<body>\\\r\\\n<a name=\\\"13312\\\"></a>\\\r\\\n<h1>抓取网页内容生成Kindle电子书</h1>\\\r\\\n\\\r\\\n<div>\\\n<span style=\\\"word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;\\\"><br/><div style=\\\"font-size: 16px\\\"><div style=\\\"font-family:sans-serif;\\\"><div style=\\\"font-family:'Helvetica Neue', Helvetica, Arial, 'Hiragino Sans GB', 'Hiragino Sans GB W3', 'WenQuanYi Micro Hei', 'Microsoft YaHei UI', 'Microsoft YaHei', sans-serif;\\\"><div><p style=\\\"font-size:16px;line-height:1.8em;color:rgb(90, 90, 90);\\\">自从买了kindle后，总是想着如何最大效用发挥其效用。虽然多看上有很多书可以购买，网上也有很多免费的电子书，但是仍然有很多感兴趣的内容是以网页的形式存在的。例如<a href=\\\"http://chimera.labs.oreilly.com/books/\\\" style=\\\"text-decoration:none;color:rgb(0, 136, 204);\\\">O’Reilly Atlas</a>就提供了诸多电子书，但是只提供免费的在线阅读；另外还有很多资料或文档都只有网页形式。于是就希望通过某种方法讲这些在线资料转为epub或mobi格式，以便在kindle上阅读。这篇文章介绍了如何借助calibre并编写少量代码来达到这个目的。</p><h1 style=\\\"font-size:2em;font-weight:normal;color:rgb(42, 42, 42);\\\">Calibre</h1><h2 style=\\\"font-weight:normal;color:rgb(42, 42, 42);\\\">Calibre简介</h2><p style=\\\"font-size:16px;line-height:1.8em;color:rgb(90, 90, 90);\\\"><a href=\\\"http://calibre-ebook.com/\\\" style=\\\"text-decoration:none;color:rgb(0, 136, 204);\\\">Calibre</a>是一个免费的电子书管理工具，可以兼容Windows, OS X及Linux，令人欣喜的是，除了GUI外，calibre还提供了诸多命令行工具，其中的ebook-convert命令可以根据用户编写的recipes文件（实际是python代码）抓取指定页面内容并生成mobi等格式的电子书。通过编写recipes可以自定制抓取行为，以适应不同的网页结构。</p><h2 style=\\\"font-weight:normal;color:rgb(42, 42, 42);\\\">安装Calibre</h2><p style=\\\"font-size:16px;line-height:1.8em;color:rgb(90, 90, 90);\\\">Calibre的下载地址是<a href=\\\"http://calibre-ebook.com/download\\\" style=\\\"text-decoration:none;color:rgb(0, 136, 204);\\\">http://calibre-ebook.com/download</a>，可以根据自己的操作系统下载相应的安装程序。</p><p style=\\\"font-size:16px;line-height:1.8em;color:rgb(90, 90, 90);\\\">如果是Linux操作系统，还可以通过软件仓库安装：</p><p style=\\\"font-size:16px;line-height:1.8em;color:rgb(90, 90, 90);\\\">Archlinux：</p><pre style=\\\"font-family:Menlo, Monaco, 'Andale Mono', 'lucida console', 'Courier New', monospace;font-size:11px;white-space:pre-wrap;word-wrap:break-word;padding:10px;border:1px solid rgb(225, 225, 232);background-color:rgb(4, 32, 41);border-radius:4px;\\\"></pre><ol style=\\\"color:rgb(76, 102, 108);margin:0px;\\\"><li style=\\\"line-height:18px;padding-left:12px;margin:0px;color:rgb(90, 90, 90);\\\"><span style=\\\"color:rgb(38, 139, 210);\\\">pacman</span> <span style=\\\"color:rgb(131, 148, 150);\\\">-</span><span style=\\\"color:rgb(38, 139, 210);\\\">S calibre</span></li></ol><p style=\\\"font-size:16px;line-height:1.8em;color:rgb(90, 90, 90);\\\">Debian/Ubuntu：</p><pre style=\\\"font-family:Menlo, Monaco, 'Andale Mono', 'lucida console', 'Courier New', monospace;font-size:11px;white-space:pre-wrap;word-wrap:break-word;padding:10px;border:1px solid rgb(225, 225, 232);background-color:rgb(4, 32, 41);border-radius:4px;\\\"></pre><ol style=\\\"color:rgb(76, 102, 108);margin:0px;\\\"><li style=\\\"line-height:18px;padding-left:12px;margin:0px;color:rgb(90, 90, 90);\\\"><span style=\\\"color:rgb(38, 139, 210);\\\">apt</span><span style=\\\"color:rgb(131, 148, 150);\\\">-</span><span style=\\\"color:rgb(38, 139, 210);\\\">get install calibre</span></li></ol><p style=\\\"font-size:16px;line-height:1.8em;color:rgb(90, 90, 90);\\\">RedHat/Fedora/CentOS：</p><pre style=\\\"font-family:Menlo, Monaco, 'Andale Mono', 'lucida console', 'Courier New', monospace;font-size:11px;white-space:pre-wrap;word-wrap:break-word;padding:10px;border:1px solid rgb(225, 225, 232);background-color:rgb(4, 32, 41);border-radius:4px;\\\"></pre><ol style=\\\"color:rgb(76, 102, 108);margin:0px;\\\"><li style=\\\"line-height:18px;padding-left:12px;margin:0px;color:rgb(90, 90, 90);\\\"><span style=\\\"color:rgb(38, 139, 210);\\\">yum</span> <span style=\\\"color:rgb(131, 148, 150);\\\">-</span><span style=\\\"color:rgb(38, 139, 210);\\\">y install calibre</span></li></ol><p style=\\\"font-size:16px;line-height:1.8em;color:rgb(90, 90, 90);\\\">注意，如果你使用OSX，需要单独安装<a href=\\\"http://manual.calibre-ebook.com/cli/cli-index.html\\\" style=\\\"text-decoration:none;color:rgb(0, 136, 204);\\\">Command Line Tool</a>。</p><h1 style=\\\"font-size:2em;font-weight:normal;color:rgb(42, 42, 42);\\\">抓取网页生成电子书</h1><p style=\\\"font-size:16px;line-height:1.8em;color:rgb(90, 90, 90);\\\">下面以<a href=\\\"http://chimera.labs.oreilly.com/books/1230000000561\\\" style=\\\"text-decoration:none;color:rgb(0, 136, 204);\\\">Git Pocket Guide</a>为例，说明如何通过calibre从网页生成电子书。</p><h2 style=\\\"font-weight:normal;color:rgb(42, 42, 42);\\\">找到index页</h2><p style=\\\"font-size:16px;line-height:1.8em;color:rgb(90, 90, 90);\\\">要抓取整本书，第一件事就是找到index页，这个页面一般是Table of Contents，也就是目录页，其中每个目录项链接到相应内容页。index页将会指导抓取哪些页面以及生成电子书时内容组织顺序。在这个例子中，index页面是<a href=\\\"http://chimera.labs.oreilly.com/books/1230000000561/index.html\\\" style=\\\"text-decoration:none;color:rgb(0, 136, 204);\\\">http://chimera.labs.oreilly.com/books/1230000000561/index.html</a>。</p><h2 style=\\\"font-weight:normal;color:rgb(42, 42, 42);\\\">编写recipes</h2><p style=\\\"font-size:16px;line-height:1.8em;color:rgb(90, 90, 90);\\\">Recipes是一个以recipe为扩展名的脚本，内容实际上是一段python代码，用来定义calibre抓取页面的范围和行为，下面是用于抓取Git Pocket Guide的recipes：</p><pre style=\\\"font-family:Menlo, Monaco, 'Andale Mono', 'lucida console', 'Courier New', monospace;font-size:11px;white-space:pre-wrap;word-wrap:break-word;padding:10px;border:1px solid rgb(225, 225, 232);background-color:rgb(4, 32, 41);border-radius:4px;\\\"></pre><ol style=\\\"color:rgb(76, 102, 108);margin:0px;\\\"><li style=\\\"line-height:18px;padding-left:12px;margin:0px;color:rgb(90, 90, 90);\\\"><span style=\\\"color:rgb(203, 75, 22);\\\">from</span> <span style=\\\"color:rgb(38, 139, 210);\\\">calibre</span><span style=\\\"color:rgb(131, 148, 150);\\\">.</span><span style=\\\"color:rgb(38, 139, 210);\\\">web</span><span style=\\\"color:rgb(131, 148, 150);\\\">.</span><span style=\\\"color:rgb(38, 139, 210);\\\">feeds</span><span style=\\\"color:rgb(131, 148, 150);\\\">.</span><span style=\\\"color:rgb(38, 139, 210);\\\">recipes</span> <span style=\\\"color:rgb(203, 75, 22);\\\">import</span> <span style=\\\"color:rgb(181, 137, 0);\\\">BasicNewsRecipe</span></li><li style=\\\"line-height:18px;padding-left:12px;margin:0px;color:rgb(90, 90, 90);\\\"><span style=\\\"color:rgb(38, 139, 210);\\\"> </span></li><li style=\\\"line-height:18px;padding-left:12px;margin:0px;color:rgb(90, 90, 90);\\\"><span style=\\\"color:rgb(203, 75, 22);\\\">class</span> <span style=\\\"color:rgb(181, 137, 0);\\\">Git_Pocket_Guide</span><span style=\\\"color:rgb(131, 148, 150);\\\">(</span><span style=\\\"color:rgb(181, 137, 0);\\\">BasicNewsRecipe</span><span style=\\\"color:rgb(131, 148, 150);\\\">):</span></li><li style=\\\"line-height:18px;padding-left:12px;margin:0px;color:rgb(90, 90, 90);\\\"><span style=\\\"color:rgb(38, 139, 210);\\\"> </span></li><li style=\\\"line-height:18px;padding-left:12px;margin:0px;color:rgb(90, 90, 90);\\\"><span style=\\\"color:rgb(38, 139, 210);\\\">title</span> <span style=\\\"color:rgb(131, 148, 150);\\\">=</span> <span style=\\\"color:rgb(42, 161, 152);\\\">'Git Pocket Guide'</span></li><li style=\\\"line-height:18px;padding-left:12px;margin:0px;color:rgb(90, 90, 90);\\\"><span style=\\\"color:rgb(38, 139, 210);\\\">description</span> <span style=\\\"color:rgb(131, 148, 150);\\\">=</span> <span style=\\\"color:rgb(42, 161, 152);\\\">''</span></li><li style=\\\"line-height:18px;padding-left:12px;margin:0px;color:rgb(90, 90, 90);\\\"><span style=\\\"color:rgb(38, 139, 210);\\\">cover_url</span> <span style=\\\"color:rgb(131, 148, 150);\\\">=</span> <span style=\\\"color:rgb(42, 161, 152);\\\">'http://akamaicovers.oreilly.com/images/0636920024972/lrg.jpg'</span></li><li style=\\\"line-height:18px;padding-left:12px;margin:0px;color:rgb(90, 90, 90);\\\"><span style=\\\"color:rgb(38, 139, 210);\\\"> </span></li><li style=\\\"line-height:18px;padding-left:12px;margin:0px;color:rgb(90, 90, 90);\\\"><span style=\\\"color:rgb(38, 139, 210);\\\">url_prefix</span> <span style=\\\"color:rgb(131, 148, 150);\\\">=</span> <span style=\\\"color:rgb(42, 161, 152);\\\">'http://chimera.labs.oreilly.com/books/1230000000561/'</span></li><li style=\\\"line-height:18px;padding-left:12px;margin:0px;color:rgb(90, 90, 90);\\\"><span style=\\\"color:rgb(38, 139, 210);\\\">no_stylesheets</span> <span style=\\\"color:rgb(131, 148, 150);\\\">=</span> <span style=\\\"color:rgb(203, 75, 22);\\\">True</span></li><li style=\\\"line-height:18px;padding-left:12px;margin:0px;color:rgb(90, 90, 90);\\\"><span style=\\\"color:rgb(38, 139, 210);\\\">keep_only_tags</span> <span style=\\\"color:rgb(131, 148, 150);\\\">=</span> <span style=\\\"color:rgb(131, 148, 150);\\\">[{</span> <span style=\\\"color:rgb(42, 161, 152);\\\">'class'</span><span style=\\\"color:rgb(131, 148, 150);\\\">:</span> <span style=\\\"color:rgb(42, 161, 152);\\\">'chapter'</span> <span style=\\\"color:rgb(131, 148, 150);\\\">}]</span></li><li style=\\\"line-height:18px;padding-left:12px;margin:0px;color:rgb(90, 90, 90);\\\"><span style=\\\"color:rgb(38, 139, 210);\\\"> </span></li><li style=\\\"line-height:18px;padding-left:12px;margin:0px;color:rgb(90, 90, 90);\\\"><span style=\\\"color:rgb(203, 75, 22);\\\">def</span> <span style=\\\"color:rgb(38, 139, 210);\\\">get_title</span><span style=\\\"color:rgb(131, 148, 150);\\\">(</span><span style=\\\"color:rgb(38, 139, 210);\\\">self</span><span style=\\\"color:rgb(131, 148, 150);\\\">,</span> <span style=\\\"color:rgb(38, 139, 210);\\\">link</span><span style=\\\"color:rgb(131, 148, 150);\\\">):</span></li><li style=\\\"line-height:18px;padding-left:12px;margin:0px;color:rgb(90, 90, 90);\\\"><span style=\\\"color:rgb(203, 75, 22);\\\">return</span> <span style=\\\"color:rgb(38, 139, 210);\\\">link</span><span style=\\\"color:rgb(131, 148, 150);\\\">.</span><span style=\\\"color:rgb(38, 139, 210);\\\">contents</span><span style=\\\"color:rgb(131, 148, 150);\\\">[</span><span style=\\\"color:rgb(42, 161, 152);\\\">0</span><span style=\\\"color:rgb(131, 148, 150);\\\">].</span><span style=\\\"color:rgb(38, 139, 210);\\\">strip</span><span style=\\\"color:rgb(131, 148, 150);\\\">()</span></li><li style=\\\"line-height:18px;padding-left:12px;margin:0px;color:rgb(90, 90, 90);\\\"><span style=\\\"color:rgb(38, 139, 210);\\\"> </span></li><li style=\\\"line-height:18px;padding-left:12px;margin:0px;color:rgb(90, 90, 90);\\\"><span style=\\\"color:rgb(203, 75, 22);\\\">def</span> <span style=\\\"color:rgb(38, 139, 210);\\\">parse_index</span><span style=\\\"color:rgb(131, 148, 150);\\\">(</span><span style=\\\"color:rgb(38, 139, 210);\\\">self</span><span style=\\\"color:rgb(131, 148, 150);\\\">):</span></li><li style=\\\"line-height:18px;padding-left:12px;margin:0px;color:rgb(90, 90, 90);\\\"><span style=\\\"color:rgb(38, 139, 210);\\\">soup</span> <span style=\\\"color:rgb(131, 148, 150);\\\">=</span> <span style=\\\"color:rgb(38, 139, 210);\\\">self</span><span style=\\\"color:rgb(131, 148, 150);\\\">.</span><span style=\\\"color:rgb(38, 139, 210);\\\">index_to_soup</span><span style=\\\"color:rgb(131, 148, 150);\\\">(</span><span style=\\\"color:rgb(38, 139, 210);\\\">self</span><span style=\\\"color:rgb(131, 148, 150);\\\">.</span><span style=\\\"color:rgb(38, 139, 210);\\\">url_prefix</span> <span style=\\\"color:rgb(131, 148, 150);\\\">+</span> <span style=\\\"color:rgb(42, 161, 152);\\\">'index.html'</span><span style=\\\"color:rgb(131, 148, 150);\\\">)</span></li><li style=\\\"line-height:18px;padding-left:12px;margin:0px;color:rgb(90, 90, 90);\\\"><span style=\\\"color:rgb(38, 139, 210);\\\"> </span></li><li style=\\\"line-height:18px;padding-left:12px;margin:0px;color:rgb(90, 90, 90);\\\"><span style=\\\"color:rgb(38, 139, 210);\\\">div</span> <span style=\\\"color:rgb(131, 148, 150);\\\">=</span> <span style=\\\"color:rgb(38, 139, 210);\\\">soup</span><span style=\\\"color:rgb(131, 148, 150);\\\">.</span><span style=\\\"color:rgb(38, 139, 210);\\\">find</span><span style=\\\"color:rgb(131, 148, 150);\\\">(</span><span style=\\\"color:rgb(42, 161, 152);\\\">'div'</span><span style=\\\"color:rgb(131, 148, 150);\\\">,</span> <span style=\\\"color:rgb(131, 148, 150);\\\">{</span> <span style=\\\"color:rgb(42, 161, 152);\\\">'class'</span><span style=\\\"color:rgb(131, 148, 150);\\\">:</span> <span style=\\\"color:rgb(42, 161, 152);\\\">'toc'</span> <span style=\\\"color:rgb(131, 148, 150);\\\">})</span></li><li style=\\\"line-height:18px;padding-left:12px;margin:0px;color:rgb(90, 90, 90);\\\"><span style=\\\"color:rgb(38, 139, 210);\\\"> </span></li><li style=\\\"line-height:18px;padding-left:12px;margin:0px;color:rgb(90, 90, 90);\\\"><span style=\\\"color:rgb(38, 139, 210);\\\">articles</span> <span style=\\\"color:rgb(131, 148, 150);\\\">=</span> <span style=\\\"color:rgb(131, 148, 150);\\\">[]</span></li><li style=\\\"line-height:18px;padding-left:12px;margin:0px;color:rgb(90, 90, 90);\\\"><span style=\\\"color:rgb(203, 75, 22);\\\">for</span> <span style=\\\"color:rgb(38, 139, 210);\\\">link</span> <span style=\\\"color:rgb(203, 75, 22);\\\">in</span> <span style=\\\"color:rgb(38, 139, 210);\\\">div</span><span style=\\\"color:rgb(131, 148, 150);\\\">.</span><span style=\\\"color:rgb(38, 139, 210);\\\">findAll</span><span style=\\\"color:rgb(131, 148, 150);\\\">(</span><span style=\\\"color:rgb(42, 161, 152);\\\">'a'</span><span style=\\\"color:rgb(131, 148, 150);\\\">):</span></li><li style=\\\"line-height:18px;padding-left:12px;margin:0px;color:rgb(90, 90, 90);\\\"><span style=\\\"color:rgb(203, 75, 22);\\\">if</span> <span style=\\\"color:rgb(42, 161, 152);\\\">'#'</span> <span style=\\\"color:rgb(203, 75, 22);\\\">in</span> <span style=\\\"color:rgb(38, 139, 210);\\\">link</span><span style=\\\"color:rgb(131, 148, 150);\\\">[</span><span style=\\\"color:rgb(42, 161, 152);\\\">'href'</span><span style=\\\"color:rgb(131, 148, 150);\\\">]:</span></li><li style=\\\"line-height:18px;padding-left:12px;margin:0px;color:rgb(90, 90, 90);\\\"><span style=\\\"color:rgb(203, 75, 22);\\\">continue</span></li><li style=\\\"line-height:18px;padding-left:12px;margin:0px;color:rgb(90, 90, 90);\\\"><span style=\\\"color:rgb(38, 139, 210);\\\"> </span></li><li style=\\\"line-height:18px;padding-left:12px;margin:0px;color:rgb(90, 90, 90);\\\"><span style=\\\"color:rgb(203, 75, 22);\\\">if</span> <span style=\\\"color:rgb(203, 75, 22);\\\">not</span> <span style=\\\"color:rgb(42, 161, 152);\\\">'ch'</span> <span style=\\\"color:rgb(203, 75, 22);\\\">in</span> <span style=\\\"color:rgb(38, 139, 210);\\\">link</span><span style=\\\"color:rgb(131, 148, 150);\\\">[</span><span style=\\\"color:rgb(42, 161, 152);\\\">'href'</span><span style=\\\"color:rgb(131, 148, 150);\\\">]:</span></li><li style=\\\"line-height:18px;padding-left:12px;margin:0px;color:rgb(90, 90, 90);\\\"><span style=\\\"color:rgb(203, 75, 22);\\\">continue</span></li><li style=\\\"line-height:18px;padding-left:12px;margin:0px;color:rgb(90, 90, 90);\\\"><span style=\\\"color:rgb(38, 139, 210);\\\"> </span></li><li style=\\\"line-height:18px;padding-left:12px;margin:0px;color:rgb(90, 90, 90);\\\"><span style=\\\"color:rgb(38, 139, 210);\\\">til</span> <span style=\\\"color:rgb(131, 148, 150);\\\">=</span> <span style=\\\"color:rgb(38, 139, 210);\\\">self</span><span style=\\\"color:rgb(131, 148, 150);\\\">.</span><span style=\\\"color:rgb(38, 139, 210);\\\">get_title</span><span style=\\\"color:rgb(131, 148, 150);\\\">(</span><span style=\\\"color:rgb(38, 139, 210);\\\">link</span><span style=\\\"color:rgb(131, 148, 150);\\\">)</span></li><li style=\\\"line-height:18px;padding-left:12px;margin:0px;color:rgb(90, 90, 90);\\\"><span style=\\\"color:rgb(38, 139, 210);\\\">url</span> <span style=\\\"color:rgb(131, 148, 150);\\\">=</span> <span style=\\\"color:rgb(38, 139, 210);\\\">self</span><span style=\\\"color:rgb(131, 148, 150);\\\">.</span><span style=\\\"color:rgb(38, 139, 210);\\\">url_prefix</span> <span style=\\\"color:rgb(131, 148, 150);\\\">+</span> <span style=\\\"color:rgb(38, 139, 210);\\\">link</span><span style=\\\"color:rgb(131, 148, 150);\\\">[</span><span style=\\\"color:rgb(42, 161, 152);\\\">'href'</span><span style=\\\"color:rgb(131, 148, 150);\\\">]</span></li><li style=\\\"line-height:18px;padding-left:12px;margin:0px;color:rgb(90, 90, 90);\\\"><span style=\\\"color:rgb(38, 139, 210);\\\">a</span> <span style=\\\"color:rgb(131, 148, 150);\\\">=</span> <span style=\\\"color:rgb(131, 148, 150);\\\">{</span> <span style=\\\"color:rgb(42, 161, 152);\\\">'title'</span><span style=\\\"color:rgb(131, 148, 150);\\\">:</span> <span style=\\\"color:rgb(38, 139, 210);\\\">til</span><span style=\\\"color:rgb(131, 148, 150);\\\">,</span> <span style=\\\"color:rgb(42, 161, 152);\\\">'url'</span><span style=\\\"color:rgb(131, 148, 150);\\\">:</span> <span style=\\\"color:rgb(38, 139, 210);\\\">url</span> <span style=\\\"color:rgb(131, 148, 150);\\\">}</span></li><li style=\\\"line-height:18px;padding-left:12px;margin:0px;color:rgb(90, 90, 90);\\\"><span style=\\\"color:rgb(38, 139, 210);\\\"> </span></li><li style=\\\"line-height:18px;padding-left:12px;margin:0px;color:rgb(90, 90, 90);\\\"><span style=\\\"color:rgb(38, 139, 210);\\\">articles</span><span style=\\\"color:rgb(131, 148, 150);\\\">.</span><span style=\\\"color:rgb(38, 139, 210);\\\">append</span><span style=\\\"color:rgb(131, 148, 150);\\\">(</span><span style=\\\"color:rgb(38, 139, 210);\\\">a</span><span style=\\\"color:rgb(131, 148, 150);\\\">)</span></li><li style=\\\"line-height:18px;padding-left:12px;margin:0px;color:rgb(90, 90, 90);\\\"><span style=\\\"color:rgb(38, 139, 210);\\\"> </span></li><li style=\\\"line-height:18px;padding-left:12px;margin:0px;color:rgb(90, 90, 90);\\\"><span style=\\\"color:rgb(38, 139, 210);\\\">ans</span> <span style=\\\"color:rgb(131, 148, 150);\\\">=</span> <span style=\\\"color:rgb(131, 148, 150);\\\">[(</span><span style=\\\"color:rgb(42, 161, 152);\\\">'Git_Pocket_Guide'</span><span style=\\\"color:rgb(131, 148, 150);\\\">,</span> <span style=\\\"color:rgb(38, 139, 210);\\\">articles</span><span style=\\\"color:rgb(131, 148, 150);\\\">)]</span></li><li style=\\\"line-height:18px;padding-left:12px;margin:0px;color:rgb(90, 90, 90);\\\"><span style=\\\"color:rgb(38, 139, 210);\\\"> </span></li><li style=\\\"line-height:18px;padding-left:12px;margin:0px;color:rgb(90, 90, 90);\\\"><span style=\\\"color:rgb(203, 75, 22);\\\">return</span> <span style=\\\"color:rgb(38, 139, 210);\\\">ans</span></li></ol><p style=\\\"font-size:16px;line-height:1.8em;color:rgb(90, 90, 90);\\\">下面分别解释代码中不同部分。</p><h3 style=\\\"font-weight:normal;color:rgb(42, 42, 42);\\\">总体结构</h3><p style=\\\"font-size:16px;line-height:1.8em;color:rgb(90, 90, 90);\\\">总体来看，一个recipes就是一个python class，只不过这个class必须继承calibre.web.feeds.recipes.BasicNewsRecipe。</p><h3 style=\\\"font-weight:normal;color:rgb(42, 42, 42);\\\">parse_index</h3><p style=\\\"font-size:16px;line-height:1.8em;color:rgb(90, 90, 90);\\\">整个recipes的核心方法是parse_index，也是recipes唯一必须实现的方法。这个方法的目标是通过分析index页面的内容，返回一个稍显复杂的数据结构（稍后介绍），这个数据结构定义了整个电子书的内容及内容组织顺序。</p><h3 style=\\\"font-weight:normal;color:rgb(42, 42, 42);\\\">总体属性设置</h3><p style=\\\"font-size:16px;line-height:1.8em;color:rgb(90, 90, 90);\\\">在class的开始，定义了一些全局属性：</p><pre style=\\\"font-family:Menlo, Monaco, 'Andale Mono', 'lucida console', 'Courier New', monospace;font-size:11px;white-space:pre-wrap;word-wrap:break-word;padding:10px;border:1px solid rgb(225, 225, 232);background-color:rgb(4, 32, 41);border-radius:4px;\\\"></pre><ol style=\\\"color:rgb(76, 102, 108);margin:0px;\\\"><li style=\\\"line-height:18px;padding-left:12px;margin:0px;color:rgb(90, 90, 90);\\\"><span style=\\\"color:rgb(38, 139, 210);\\\">title</span> <span style=\\\"color:rgb(131, 148, 150);\\\">=</span> <span style=\\\"color:rgb(42, 161, 152);\\\">'Git Pocket Guide'</span></li><li style=\\\"line-height:18px;padding-left:12px;margin:0px;color:rgb(90, 90, 90);\\\"><span style=\\\"color:rgb(38, 139, 210);\\\">description</span> <span style=\\\"color:rgb(131, 148, 150);\\\">=</span> <span style=\\\"color:rgb(42, 161, 152);\\\">''</span></li><li style=\\\"line-height:18px;padding-left:12px;margin:0px;color:rgb(90, 90, 90);\\\"><span style=\\\"color:rgb(38, 139, 210);\\\">cover_url</span> <span style=\\\"color:rgb(131, 148, 150);\\\">=</span> <span style=\\\"color:rgb(42, 161, 152);\\\">'http://akamaicovers.oreilly.com/images/0636920024972/lrg.jpg'</span></li><li style=\\\"line-height:18px;padding-left:12px;margin:0px;color:rgb(90, 90, 90);\\\"><span style=\\\"color:rgb(38, 139, 210);\\\"> </span></li><li style=\\\"line-height:18px;padding-left:12px;margin:0px;color:rgb(90, 90, 90);\\\"><span style=\\\"color:rgb(38, 139, 210);\\\">url_prefix</span> <span style=\\\"color:rgb(131, 148, 150);\\\">=</span> <span style=\\\"color:rgb(42, 161, 152);\\\">'http://chimera.labs.oreilly.com/books/1230000000561/'</span></li><li style=\\\"line-height:18px;padding-left:12px;margin:0px;color:rgb(90, 90, 90);\\\"><span style=\\\"color:rgb(38, 139, 210);\\\">no_stylesheets</span> <span style=\\\"color:rgb(131, 148, 150);\\\">=</span> <span style=\\\"color:rgb(203, 75, 22);\\\">True</span></li><li style=\\\"line-height:18px;padding-left:12px;margin:0px;color:rgb(90, 90, 90);\\\"><span style=\\\"color:rgb(38, 139, 210);\\\">keep_only_tags</span> <span style=\\\"color:rgb(131, 148, 150);\\\">=</span> <span style=\\\"color:rgb(131, 148, 150);\\\">[{</span> <span style=\\\"color:rgb(42, 161, 152);\\\">'class'</span><span style=\\\"color:rgb(131, 148, 150);\\\">:</span> <span style=\\\"color:rgb(42, 161, 152);\\\">'chapter'</span> <span style=\\\"color:rgb(131, 148, 150);\\\">}]</span></li></ol><ul><li style=\\\"line-height:1.8em;margin:7px 0px;color:rgb(90, 90, 90);\\\">title：电子书标题</li><li style=\\\"line-height:1.8em;margin:7px 0px;color:rgb(90, 90, 90);\\\">description：电子书描述</li><li style=\\\"line-height:1.8em;margin:7px 0px;color:rgb(90, 90, 90);\\\">cover_url：电子书的封面图片</li><li style=\\\"line-height:1.8em;margin:7px 0px;color:rgb(90, 90, 90);\\\">url_prefix：这是我自用的属性，是内容页面的前缀，用于后面拼装内容页的完整url</li><li style=\\\"line-height:1.8em;margin:7px 0px;color:rgb(90, 90, 90);\\\">no_stylesheets：不要使用页面CSS样式</li><li style=\\\"line-height:1.8em;margin:7px 0px;color:rgb(90, 90, 90);\\\">keep_only_tags：这一行告诉calibre分析index页时仅考虑class属性为“chapter”的DOM元素，如果你看index页的源码会发现这对应一级标题。之所以这样是因为在这个例子中，index页面每个一级标题对应一个独立内容页，而二级标题仅链接到页面中某个锚点（anchor），所以仅需考虑一级标题</li></ul><h3 style=\\\"font-weight:normal;color:rgb(42, 42, 42);\\\">parse_index返回值</h3><p style=\\\"font-size:16px;line-height:1.8em;color:rgb(90, 90, 90);\\\">下面介绍parse_index需要通过分析index页面返回的数据结构。</p><p style=\\\"font-size:16px;line-height:1.8em;color:rgb(90, 90, 90);text-align:center;\\\"><img src=\\\"抓取网页内容生成Kindle电子书_files/Image.png\\\" type=\\\"image/png\\\" data-filename=\\\"Image.png\\\" height=\\\"368\\\" style=\\\"border:0px;cursor: default;cursor: default;\\\" width=\\\"570\\\"/></p><p style=\\\"font-size:16px;line-height:1.8em;color:rgb(90, 90, 90);\\\">总体返回数据结构是一个list，其中每个元素是一个tuple，一个tuple表示一卷（volume）。在这个例子中只有一卷，所以list中只有一个tuple。</p><p style=\\\"font-size:16px;line-height:1.8em;color:rgb(90, 90, 90);\\\">每个tuple有两个元素，第一个元素是卷名，第二个元素是一个list，list中每个元素是一个map，表示一章（chapter），map中有两个元素：title和url，title是章节标题，url是章节所在内容页的url。</p><p style=\\\"font-size:16px;line-height:1.8em;color:rgb(90, 90, 90);\\\">Calibre会根据parse_index的返回结果抓取并组织整个书，并且会自行抓取并处理内容中外链的图片。</p><p style=\\\"font-size:16px;line-height:1.8em;color:rgb(90, 90, 90);\\\">整个parse_index使用soup解析index页并生成上述数据结构。</p><h3 style=\\\"font-weight:normal;color:rgb(42, 42, 42);\\\">更多</h3><p style=\\\"font-size:16px;line-height:1.8em;color:rgb(90, 90, 90);\\\">上面是最基本的recipes，想了解更多的使用方法，可以参考<a href=\\\"http://manual.calibre-ebook.com/news_recipe.html\\\" style=\\\"text-decoration:none;color:rgb(0, 136, 204);\\\">API文档</a>。</p><h2 style=\\\"font-weight:normal;color:rgb(42, 42, 42);\\\">生成mobi</h2><p style=\\\"font-size:16px;line-height:1.8em;color:rgb(90, 90, 90);\\\">编写好recipes后，在命令行下通过如下命令即可生成电子书：</p><pre style=\\\"font-family:Menlo, Monaco, 'Andale Mono', 'lucida console', 'Courier New', monospace;font-size:11px;white-space:pre-wrap;word-wrap:break-word;padding:10px;border:1px solid rgb(225, 225, 232);background-color:rgb(4, 32, 41);border-radius:4px;\\\"></pre><ol style=\\\"color:rgb(76, 102, 108);margin:0px;\\\"><li style=\\\"line-height:18px;padding-left:12px;margin:0px;color:rgb(90, 90, 90);\\\"><span style=\\\"color:rgb(38, 139, 210);\\\">ebook</span><span style=\\\"color:rgb(131, 148, 150);\\\">-</span><span style=\\\"color:rgb(38, 139, 210);\\\">convert</span> <span style=\\\"color:rgb(181, 137, 0);\\\">Git_Pocket_Guide</span><span style=\\\"color:rgb(131, 148, 150);\\\">.</span><span style=\\\"color:rgb(38, 139, 210);\\\">recipe</span> <span style=\\\"color:rgb(181, 137, 0);\\\">Git_Pocket_Guide</span><span style=\\\"color:rgb(131, 148, 150);\\\">.</span><span style=\\\"color:rgb(38, 139, 210);\\\">mobi</span></li></ol><p style=\\\"font-size:16px;line-height:1.8em;color:rgb(90, 90, 90);\\\">即可生成mobi格式的电子书。ebook-convert会根据recipes代码自行抓取相关内容并组织结构。</p><h1 style=\\\"font-size:2em;font-weight:normal;color:rgb(42, 42, 42);\\\">最终效果</h1><p style=\\\"font-size:16px;line-height:1.8em;color:rgb(90, 90, 90);\\\">下面是在kindle上看到的效果。</p><p style=\\\"font-size:16px;line-height:1.8em;color:rgb(90, 90, 90);\\\">目录</p><p style=\\\"font-size:16px;line-height:1.8em;color:rgb(90, 90, 90);text-align:center;\\\"><img src=\\\"抓取网页内容生成Kindle电子书_files/Image.jpg\\\" type=\\\"image/jpeg\\\" data-filename=\\\"Image.jpg\\\" height=\\\"675\\\" style=\\\"border:0px;cursor: default;cursor: default;\\\" width=\\\"500\\\"/></p><p style=\\\"font-size:16px;line-height:1.8em;color:rgb(90, 90, 90);\\\">内容一</p><p style=\\\"font-size:16px;line-height:1.8em;color:rgb(90, 90, 90);text-align:center;\\\"><img src=\\\"抓取网页内容生成Kindle电子书_files/Image [1].jpg\\\" type=\\\"image/jpeg\\\" data-filename=\\\"Image.jpg\\\" height=\\\"675\\\" style=\\\"border:0px;cursor: default;cursor: default;\\\" width=\\\"500\\\"/></p><p style=\\\"font-size:16px;line-height:1.8em;color:rgb(90, 90, 90);\\\">内容二</p><p style=\\\"font-size:16px;line-height:1.8em;color:rgb(90, 90, 90);text-align:center;\\\"><img src=\\\"抓取网页内容生成Kindle电子书_files/Image [2].jpg\\\" type=\\\"image/jpeg\\\" data-filename=\\\"Image.jpg\\\" height=\\\"675\\\" style=\\\"border:0px;cursor: default;cursor: default;\\\" width=\\\"500\\\"/></p><p style=\\\"font-size:16px;line-height:1.8em;color:rgb(90, 90, 90);\\\">含有图片的页</p><p style=\\\"font-size:16px;line-height:1.8em;color:rgb(90, 90, 90);text-align:center;\\\"><img src=\\\"抓取网页内容生成Kindle电子书_files/Image [3].jpg\\\" type=\\\"image/jpeg\\\" data-filename=\\\"Image.jpg\\\" height=\\\"675\\\" style=\\\"border:0px;cursor: default;cursor: default;\\\" width=\\\"500\\\"/></p><p style=\\\"font-size:16px;line-height:1.8em;color:rgb(90, 90, 90);\\\">实际效果</p><p style=\\\"font-size:16px;line-height:1.8em;color:rgb(90, 90, 90);text-align:center;\\\"><img src=\\\"抓取网页内容生成Kindle电子书_files/Image [4].jpg\\\" type=\\\"image/jpeg\\\" data-filename=\\\"Image.jpg\\\" height=\\\"445\\\" style=\\\"border:0px;cursor: default;cursor: default;\\\" width=\\\"319\\\"/></p><h1 style=\\\"font-size:2em;font-weight:normal;color:rgb(42, 42, 42);\\\">我的recipes仓库</h1><p style=\\\"font-size:16px;line-height:1.8em;color:rgb(90, 90, 90);\\\">我在github上建了一个<a href=\\\"https://github.com/ericzhang-cn/kindle-open-books/\\\" style=\\\"text-decoration:none;color:rgb(0, 136, 204);\\\">kindle-open-books</a>，里面放了一些recipes，有我写的，也有其他同学贡献的。欢迎任何人贡献的recipes。</p></div></div></div></div><br/></span>\\\n</div></body></html>\\u0000\"]],\"start1\":0,\"start2\":0,\"length1\":0,\"length2\":25794}]"
metadata_diff: {"new":{"id":"9b6f56e48e684ee89bd5eb1a9ec1c2e9","parent_id":"f67288c3a0be4374b5d532b5dcc3aabc","latitude":"0.00000000","longitude":"0.00000000","altitude":"0.0000","author":"","source_url":"","is_todo":0,"todo_due":0,"todo_completed":0,"source":"joplin-desktop","source_application":"net.cozic.joplin-desktop","application_data":"","order":1764348856073,"user_updated_time":1764345576803,"markup_language":2,"is_shared":0,"share_id":"","conflict_original_id":"","master_key_id":"","user_data":"","deleted_time":1764365022239},"deleted":[]}
encryption_cipher_text: 
encryption_applied: 0
updated_time: 2025-11-28T21:24:52.355Z
created_time: 2025-11-28T21:24:52.355Z
type_: 13