{"componentChunkName":"component---src-templates-blog-post-js","path":"/web-crawler-for-hitokoto/","result":{"data":{"site":{"siteMetadata":{"title":"星雨之夜"}},"markdownRemark":{"id":"8a4c05e0-19b2-5fae-8bbf-23413e291010","excerpt":"爬虫一向都很有意思，当你把想要的内容从网络中抓取并保存下来的时候，一定会得到“占有”它的满满的幸福感 (๑´ڡ`๑) 大部分爬虫是很繁琐的，需要手动写出许多规则来过滤大部分的无效内容；有些就很简单了，可以通过网站提供的 API 来获取信息，这也是为开发者们提供的便利。本文主要记录爬取 一言 - ヒトコト 站点 API…","html":"<p>爬虫一向都很有意思，当你把想要的内容从网络中抓取并保存下来的时候，一定会得到“占有”它的满满的幸福感 (๑´ڡ`๑)</p>\n<p>大部分爬虫是很繁琐的，需要手动写出许多规则来过滤大部分的无效内容；有些就很简单了，可以通过网站提供的 API 来获取信息，这也是为开发者们提供的便利。本文主要记录爬取 <a href=\"http://hitokoto.us/\">一言 - ヒトコト</a> 站点 API 的过程。</p>\n<!-- more -->\n<h2>爬虫目标</h2>\n<p>爬取通过 API 能够得到的所有内容，基于 Node.js 。</p>\n<h2>内容存取</h2>\n<p>使用 MongoDB 存储数据，mongoose 操作数据。</p>\n<h2>代码主体</h2>\n<p>首先访问一次 API 地址：<a href=\"http://api.hitokoto.us/rand\">http://api.hitokoto.us/rand</a>，看看它到底提供了哪些数据（手动格式化了一下）：</p>\n<div class=\"gatsby-highlight\" data-language=\"json\"><pre class=\"language-json\"><code class=\"language-json\"><span class=\"token punctuation\">{</span>\n  <span class=\"token property\">\"hitokoto\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"我从小就害怕虫子\"</span><span class=\"token punctuation\">,</span>\n  <span class=\"token property\">\"cat\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"g\"</span><span class=\"token punctuation\">,</span>\n  <span class=\"token property\">\"author\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"firo\"</span><span class=\"token punctuation\">,</span>\n  <span class=\"token property\">\"source\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"小小闲\"</span><span class=\"token punctuation\">,</span>\n  <span class=\"token property\">\"like\"</span><span class=\"token operator\">:</span> <span class=\"token number\">9</span><span class=\"token punctuation\">,</span>\n  <span class=\"token property\">\"date\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"2012.07.22 12:02:01\"</span><span class=\"token punctuation\">,</span>\n  <span class=\"token property\">\"catname\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"其他\"</span><span class=\"token punctuation\">,</span>\n  <span class=\"token property\">\"id\"</span><span class=\"token operator\">:</span> <span class=\"token number\">1342929721000</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>随后就能组织写入数据库的数据结构了，与上述 json 数据格式保持一致，保存并命名为 hitokoto.js：</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">var</span> mongoose <span class=\"token operator\">=</span> <span class=\"token function\">require</span><span class=\"token punctuation\">(</span><span class=\"token string\">'mongoose'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token keyword\">var</span> Schema <span class=\"token operator\">=</span> mongoose<span class=\"token punctuation\">.</span>Schema<span class=\"token punctuation\">;</span>\n\n<span class=\"token comment\">// 新建 Schema</span>\n<span class=\"token keyword\">var</span> hitokotoSchema <span class=\"token operator\">=</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">Schema</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n  hitokoto<span class=\"token operator\">:</span> String<span class=\"token punctuation\">,</span>\n  cat<span class=\"token operator\">:</span> String<span class=\"token punctuation\">,</span>\n  author<span class=\"token operator\">:</span> String<span class=\"token punctuation\">,</span>\n  source<span class=\"token operator\">:</span> String<span class=\"token punctuation\">,</span>\n  like<span class=\"token operator\">:</span> Number<span class=\"token punctuation\">,</span>\n  date<span class=\"token operator\">:</span> String<span class=\"token punctuation\">,</span>\n  catname<span class=\"token operator\">:</span> String<span class=\"token punctuation\">,</span>\n  _id<span class=\"token operator\">:</span> Number<span class=\"token punctuation\">,</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token comment\">// 导出 model</span>\nmodule<span class=\"token punctuation\">.</span>exports <span class=\"token operator\">=</span> mongoose<span class=\"token punctuation\">.</span><span class=\"token function\">model</span><span class=\"token punctuation\">(</span><span class=\"token string\">'Hitokoto'</span><span class=\"token punctuation\">,</span> hitokotoSchema<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code></pre></div>\n<p>然后新建 index.js 文件，导入上面的数据模型，获取 API 信息并根据已经组织好的数据结构写入数据库：</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">var</span> Hitokoto <span class=\"token operator\">=</span> <span class=\"token function\">require</span><span class=\"token punctuation\">(</span><span class=\"token string\">'./hitokoto'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token keyword\">var</span> mongoose <span class=\"token operator\">=</span> <span class=\"token function\">require</span><span class=\"token punctuation\">(</span><span class=\"token string\">'mongoose'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token keyword\">var</span> http <span class=\"token operator\">=</span> <span class=\"token function\">require</span><span class=\"token punctuation\">(</span><span class=\"token string\">'http'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token comment\">// 连接数据库，首先确保已在本地运行 mongod</span>\nmongoose<span class=\"token punctuation\">.</span><span class=\"token function\">connect</span><span class=\"token punctuation\">(</span><span class=\"token string\">'mongodb://localhost/hitokoto'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\nmongoose<span class=\"token punctuation\">.</span>connection<span class=\"token punctuation\">.</span><span class=\"token function\">on</span><span class=\"token punctuation\">(</span><span class=\"token string\">'error'</span><span class=\"token punctuation\">,</span> <span class=\"token keyword\">function</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  console<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span><span class=\"token string\">'mongodb connection error'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token comment\">// 循环发送 GET 请求</span>\n<span class=\"token comment\">// 不用 setTimeout，任性，可能造成的问题暂时不管了 XD</span>\n<span class=\"token function\">setInterval</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">function</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  http\n    <span class=\"token punctuation\">.</span><span class=\"token function\">get</span><span class=\"token punctuation\">(</span><span class=\"token string\">'http://api.hitokoto.us/rand'</span><span class=\"token punctuation\">,</span> <span class=\"token keyword\">function</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">res</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n      res<span class=\"token punctuation\">.</span><span class=\"token function\">on</span><span class=\"token punctuation\">(</span><span class=\"token string\">'data'</span><span class=\"token punctuation\">,</span> <span class=\"token keyword\">function</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">chunk</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n        <span class=\"token comment\">// 以 JSON 格式取得数据</span>\n        data <span class=\"token operator\">=</span> <span class=\"token constant\">JSON</span><span class=\"token punctuation\">.</span><span class=\"token function\">parse</span><span class=\"token punctuation\">(</span>chunk<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n        <span class=\"token comment\">// 查询获取到的数据是否已经写入数据库</span>\n        Hitokoto<span class=\"token punctuation\">.</span><span class=\"token function\">find</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span> _id<span class=\"token operator\">:</span> data<span class=\"token punctuation\">.</span>id <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span> <span class=\"token keyword\">function</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">err<span class=\"token punctuation\">,</span> current</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n          <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>err<span class=\"token punctuation\">)</span> <span class=\"token keyword\">return</span> console<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span>err<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n          <span class=\"token comment\">// 是则立即返回，进行下一次读取</span>\n          <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>current<span class=\"token punctuation\">.</span>length <span class=\"token operator\">!=</span> <span class=\"token number\">0</span><span class=\"token punctuation\">)</span> <span class=\"token keyword\">return</span><span class=\"token punctuation\">;</span>\n          <span class=\"token comment\">// 否则将新数据写入数据库</span>\n          <span class=\"token keyword\">var</span> hitokoto <span class=\"token operator\">=</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">Hitokoto</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n            hitokoto<span class=\"token operator\">:</span> data<span class=\"token punctuation\">.</span>hitokoto<span class=\"token punctuation\">,</span>\n            cat<span class=\"token operator\">:</span> data<span class=\"token punctuation\">.</span>cat<span class=\"token punctuation\">,</span>\n            author<span class=\"token operator\">:</span> data<span class=\"token punctuation\">.</span>author<span class=\"token punctuation\">,</span>\n            source<span class=\"token operator\">:</span> data<span class=\"token punctuation\">.</span>source<span class=\"token punctuation\">,</span>\n            like<span class=\"token operator\">:</span> data<span class=\"token punctuation\">.</span>like<span class=\"token punctuation\">,</span>\n            date<span class=\"token operator\">:</span> data<span class=\"token punctuation\">.</span>date<span class=\"token punctuation\">,</span>\n            catname<span class=\"token operator\">:</span> data<span class=\"token punctuation\">.</span>catname<span class=\"token punctuation\">,</span>\n            _id<span class=\"token operator\">:</span> data<span class=\"token punctuation\">.</span>id<span class=\"token punctuation\">,</span>\n          <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n          hitokoto<span class=\"token punctuation\">.</span><span class=\"token function\">save</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">function</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">err</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n            <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>err<span class=\"token punctuation\">)</span> <span class=\"token keyword\">return</span> console<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span>err<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n            console<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span>data<span class=\"token punctuation\">.</span>id <span class=\"token operator\">+</span> <span class=\"token string\">' saved!'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n          <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n        <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n      <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span>\n    <span class=\"token punctuation\">.</span><span class=\"token function\">on</span><span class=\"token punctuation\">(</span><span class=\"token string\">'error'</span><span class=\"token punctuation\">,</span> <span class=\"token keyword\">function</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">err</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n      console<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span>err<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span> <span class=\"token number\">1500</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span> <span class=\"token comment\">// 读取时间间隔1.5秒</span></code></pre></div>\n<p>最后应该就可以正常运行了，保存成功的 id 值会在终端进行输出：</p>\n<div class=\"gatsby-highlight\" data-language=\"shell\"><pre class=\"language-shell\"><code class=\"language-shell\"><span class=\"token function\">npm</span> <span class=\"token function\">install</span> mongoose\nnode index.js</code></pre></div>\n<p>截止到目前为止，共获取到 483 条一言的数据，可能还有几条，也可能没有了，不知道有没有办法知道是否全部爬完，或者有更高效的方法进行爬取？</p>\n<p>其实本想把一言这么好玩的东西放进博客的，无奈审美太渣，感觉放哪儿都不好看，还是不破坏主题了，就这样吧 233</p>","frontmatter":{"title":"Hitokoto.us（一言）的 API 爬虫","date":"2015 年 05 月 05 日","description":null}}},"pageContext":{"slug":"/web-crawler-for-hitokoto/","previous":{"fields":{"slug":"/install-sublime-linter/"},"frontmatter":{"title":"整理 SublimeLinter 的安装步骤"}},"next":{"fields":{"slug":"/hexo-cfg/"},"frontmatter":{"title":"Hexo 设置备份"}}}}}