-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathindex.html
519 lines (518 loc) · 23.6 KB
/
index.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
<!DOCTYPE html>
<html lang="zh-Hans">
<head>
<meta name="generator" content="Hexo 3.9.0" />
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" />
<meta name="description" content="promise-await-yield 异步三连" />
<meta name="keywords" content="Javascript" />
<meta name="author" />
<meta name="copyright" />
<title>promise-await-yield 异步三连 | luckyray</title>
<link rel="shortcut icon" href="/favicons.ico" />
<link rel="stylesheet" href="https://luckyray-fan.github.io/css/index.css?version=1.6.1" />
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/font-awesome@latest/css/font-awesome.min.css?version=1.6.1"
/>
<link rel="dns-prefetch" href="https://cdn.staticfile.org" />
<link rel="dns-prefetch" href="https://cdn.bootcss.com" />
<link rel="dns-prefetch" href="https://creativecommons.org" />
<script src="https://cdn.bootcss.com/vue/2.6.10/vue.js"></script>
<!-- <script>window.hexoHistoryConfig = {"repo":"luckyray-fan/luckyray-fan.github.io","token":"1d5107f3e8a6dd270b60bb70ffce79485b387e53","theme":"melody"}</script> -->
<style></style>
<script>
var GLOBAL_CONFIG = {
root: '/',
algolia: undefined,
localSearch: undefined,
copy: {
success: '复制成功',
error: '复制错误',
noSupport: '浏览器不支持'
}
};
</script>
</head>
<body>
<i class="fa fa-arrow-right" id="toggle-sidebar" aria-hidden="true"></i>
<div id="sidebar">
<div class="toggle-sidebar-info text-center">
<span data-toggle="切换文章详情">切换站点概览</span>
<hr />
</div>
<div class="sidebar-toc">
<div class="sidebar-toc__title">目录</div>
<div class="sidebar-toc__progress">
<span class="progress-notice">你已经读了</span>
<span class="progress-num">0</span>
<span class="progress-percentage">%</span>
<div class="sidebar-toc__progress-bar"></div>
</div>
<div class="sidebar-toc__content">
<ol class="toc">
<li class="toc-item toc-level-2">
<a class="toc-link" href="#效果">
<span class="toc-number">1.</span>
<span class="toc-text">效果</span>
</a>
</li>
<li class="toc-item toc-level-2">
<a class="toc-link" href="#起因">
<span class="toc-number">2.</span>
<span class="toc-text">起因</span>
</a>
</li>
<li class="toc-item toc-level-2">
<a class="toc-link" href="#编写思路">
<span class="toc-number">3.</span>
<span class="toc-text">编写思路</span>
</a>
</li>
<li class="toc-item toc-level-2">
<a class="toc-link" href="#流程细节">
<span class="toc-number">4.</span>
<span class="toc-text">流程细节</span>
</a>
<ol class="toc-child">
<li class="toc-item toc-level-3">
<a class="toc-link" href="#建立整个项目基础">
<span class="toc-number">4.1.</span>
<span class="toc-text">建立整个项目基础</span>
</a>
</li>
<li class="toc-item toc-level-3">
<a class="toc-link" href="#获取需要查询的图片">
<span class="toc-number">4.2.</span>
<span class="toc-text">获取需要查询的图片</span>
</a>
</li>
<li class="toc-item toc-level-3">
<a class="toc-link" href="#建立查询方式">
<span class="toc-number">4.3.</span>
<span class="toc-text">建立查询方式</span>
</a>
</li>
<li class="toc-item toc-level-3">
<a class="toc-link" href="#下载机制">
<span class="toc-number">4.4.</span>
<span class="toc-text">下载机制</span>
</a>
</li>
<li class="toc-item toc-level-3">
<a class="toc-link" href="#错误提醒-日志打印">
<span class="toc-number">4.5.</span>
<span class="toc-text">错误提醒, 日志打印</span>
</a>
</li>
</ol>
</li>
</ol>
</div>
</div>
<div class="author-info hide">
<div class="author-info__avatar text-center"><img src="/img/avatar.png" /></div>
<div class="author-info__name text-center"></div>
<div class="author-info__description text-center">只能自己努力找乐子了</div>
<hr />
<div class="author-info-articles">
<a class="author-info-articles__archives article-meta" href="/archives">
<span class="pull-left">文章</span>
<span class="pull-right">26</span>
</a>
<a class="author-info-articles__tags article-meta" href="/tags">
<span class="pull-left">标签</span>
<span class="pull-right">8</span>
</a>
<a class="author-info-articles__categories article-meta" href="/categories">
<span class="pull-left">分类</span>
<span class="pull-right">6</span>
</a>
</div>
</div>
</div>
<div id="content-outer">
<div id="top-container" style="background-image: url(http://img.luckyray.cn/896653.jpg)">
<div id="page-header">
<span class="pull-left"><a id="site-name" href="/">luckyray</a></span>
<i class="fa fa-bars toggle-menu pull-right" aria-hidden="true"></i>
<span class="pull-right menus">
<a class="site-page" href="/">Home</a>
<a class="site-page" href="/archives">Archives</a>
<a class="site-page" href="/tags">Tags</a>
<a class="site-page" href="/categories">Categories</a>
<a class="site-page" href="/knowledge-point">知识点</a>
</span>
</div>
<div id="post-info">
<div id="post-title">nodejs 批量反向查询并下载原图</div>
<div id="post-meta">
<time class="post-meta__date">
<i class="fa fa-calendar" aria-hidden="true"></i>
2020-02-02
</time>
</div>
</div>
</div>
<div class="layout" id="content-inner">
<article id="post">
<div class="article-container" id="post-content">
<h2 id="效果">
<a href="#效果" class="headerlink" title="效果"></a>
效果
</h2>
<p>
采用了队列式的下载, 保证下载不停滞, 当搜索出的所有结果下载完成后才移动被搜索的图片
<br />
下面是第一批的结果, 截了部分图片,
另外这个是多次运行项目最后得到的结果(前期编写不完善), 从100张图片搜索共得到313张,
有4张图片无法查找到结果, 原因和改进都会在下方讲述
</p>
<blockquote>
<p>
现已经由250+图找到了700+图, 注意, 目前没有普适性(使用了七牛云, 虽然也写了 smms
但是没有使用), 项目仅供参考,
<a
href="https://github.com/luckyray-fan/picpick/tree/master"
target="_blank"
rel="noopener"
>
项目地址
</a>
</p>
</blockquote>
<p><img src="/image/picpick-1.png" alt="部分图片" /></p>
<blockquote>
<p>
<strong>代码超级无敌耦合, 意大利面式的最佳实践</strong>
😂, 由于后面会写前端可视化时改写, 所以先这样吧, 等三四月边面试边写
</p>
</blockquote>
<a id="more"></a>
<h2 id="起因">
<a href="#起因" class="headerlink" title="起因"></a>
起因
</h2>
<p>
这个项目和之前手机上传文件一样, 是有个明确的需求的, 因为经常用手机刷telegram,
平时积累了许多图片, 但是这些图片往往像素不高, 所以就得一个个查询原图下载
</p>
<h2 id="编写思路">
<a href="#编写思路" class="headerlink" title="编写思路"></a>
编写思路
</h2>
<p>目的流程: 筛选出不清晰的图片 -> 利用图片搜索结果 -> 下载</p>
<ul>
<li>筛选: 如果图片大小小于300k就搜索</li>
<li>搜索: 查询 sauce, ascii2d, iqdb</li>
<li>
下载: 解析查询结果, 使用 socket 代理建立连接下载(毕竟不少图片是 pixiv 和 twitter)
</li>
</ul>
<blockquote>
<p>
关于网站查询结果
<br />
sauce: pixiv, twitter 居多, 能找到很多其他网站
<br />
ascii: pixiv, twitter
<br />
iqdb: 各大图库, 例如 danbooru
<br />
tineye: 没能解析, 使用了 cloud 防护, 尝试了 puppteer 后放弃了,
可以手动访问然后请求带上 cookie 试试
</p>
</blockquote>
<h2 id="流程细节">
<a href="#流程细节" class="headerlink" title="流程细节"></a>
流程细节
</h2>
<p>下方编写整个项目遇到的问题和解决的方法, 如何找到bug, 如何增强功能等</p>
<h3 id="建立整个项目基础">
<a href="#建立整个项目基础" class="headerlink" title="建立整个项目基础"></a>
建立整个项目基础
</h3>
<p>
google了一下相关的查询方案, 参考了这个项目
<a
href="https://github.com/Tsuk1ko/CQ-picfinder-robot/tree/master/modules"
target="_blank"
rel="noopener"
>
CQ-picfinder-robot
</a>
, 决定使用 sauce 和 ascii 来查询, 然后项目编写一个配置文件, 项目的请求采用 Axios,
用代理的方式为 httpsAgent
</p>
<h3 id="获取需要查询的图片">
<a href="#获取需要查询的图片" class="headerlink" title="获取需要查询的图片"></a>
获取需要查询的图片
</h3>
<p>
在配置文件里写好路径, 图片文件路径
<code>source</code>
, 检测不清晰后移动的路径
<code>lowQuality</code>
, 查询完成后移动出来的路径
<code>out</code>
, 然后调用node 文件系统的 api, 使用
<code>statsync</code>
判断文件还是文件夹,
<code>file-type</code>
判断文件类型
</p>
<p>
之前决定用 sauce 来查询, 利用
<code>url</code>
字段传递想要查询的图片, 那么现在就需要一个中继的服务器, 一开始浏览了 smms, imgur
等图床, 后面决定使用早就实名好的七牛云来上传
</p>
<p><strong>遇到的问题</strong></p>
<ul>
<li>file-type 是异步的: 使用 await 获取最终返回值, 将原本同步的函数加上 async</li>
<li>
七牛云 api 是回调的方式: 这个和整体清一色 await 不一致,
为了捕获到最后执行完成然后将结果返回给外部, 使用
<code>setInterval</code>
来查询
<code>flag</code>
的状态, 如果为真, 意味着上传完成执行
<code>Promise</code>
回调中的
<code>resolve</code>
, 将值传给外部
<br />
<img src="/image/picpick-2.png" alt="回调捕捉" />
</li>
</ul>
<h3 id="建立查询方式">
<a href="#建立查询方式" class="headerlink" title="建立查询方式"></a>
建立查询方式
</h3>
<p>
使用 sauce, 利用相似度来判断第一步, 若未成功用 ascii 的色合检索来接力, 如果 ascii
也失败了的话使用 iqdb 来进行最后一步查询
</p>
<ul>
<li>
<strong>如何查询的</strong>
:
<ul>
<li>
sauce: 注册账号后可以查看其 api 说明, 当然也可以看看 github 上相关的说明,
这个是直接发请求然后解析返回的值就好了, 从返回的
<code>limit</code>
字段可以明确知道有多少的限制
</li>
<li>
ascii: 发送请求然后解析返回的页面, 可以将返回的 url 中的 color 替换为 bovw
再请求一次, 也就是获得特征检索的结果, 详细描述我写在了 github 的 ascii 文件中
</li>
<li>iqdb: 发送请求解析返回的页面</li>
</ul>
</li>
<li>
<strong>错误处理</strong>
: 因为采取的都是 await 的写法, 捕捉到错误后将错误打印然后返回一个指定的值,
外界得到返回的值判断是否成功
</li>
<li>
<strong>sauce 429</strong>
:
<ul>
<li>
<strong>代理池</strong>
, 编写 proxyPool, 解析各大公开代理的网站
<ul>
<li>
这些网站对于爬虫似乎限制挺大的, 因此加了出现错误延时再试的机制, 访问也都带了
<code>user-agent</code>
和
<code>refer</code>
, 对于使用了 cloud 防护的需要手动获取 cookie, 更多可以查到国内可用 ip
的解析网站可以去 github 找一找
</li>
<li>
测试 ip 的可用性是通过访问能
<a href="https://icanhazip.com/" target="_blank" rel="noopener">
返回请求的ip的网站
</a>
, 判断与现在使用的代理 ip 是否相同
</li>
<li>
部分代理网站和测试代理 ip 时连接上但是迟迟不返回, 一开始依照惯例给了
timeout, 然后发现了这个超时的区别不同, 分别有连接和读取超时, 于是采用 axios
的 cancel, 如果超过一定时间直接取消掉, 详细可以看
<a
href="https://juejin.im/post/5de0ddbf51882523467752b8"
target="_blank"
rel="noopener"
>
ECONNRESET VS ETIMEDOUT
</a>
</li>
<li>
注意不要使用 axios cancel 掉的请求捕捉错误的值来赋值, 它的 valueof
方法似乎有点问题, 会递归然后溢出
</li>
</ul>
</li>
<li>
连接重试, 每一次换一个 ip 进行请求, 这里没有使用本地 ip 的请求, 都是由 ssr 和
公开代理提供的
</li>
</ul>
</li>
<li>
<strong>iqdb 返回image type error</strong>
: iqdb 不支持某些格式的图片, 查看出错的图片, 发现后缀名和 exif 信息不匹配,
于是使用了七牛云的图片处理接口, 所有图片强制转换为 jpg
</li>
</ul>
<h3 id="下载机制">
<a href="#下载机制" class="headerlink" title="下载机制"></a>
下载机制
</h3>
<p>
根据之前反向搜索查到的网址, 解析网站获取图片地址, 然后依次下载, 如果解析失败, 使用
iqdb 专搜图库再来一次, 如果下载失败, 进行重试 (暂时完成, 初步测试没有问题)
</p>
<ul>
<li>
<strong>直接爬取 pixiv</strong>
: github 上搜索了一下, 有相关的库, 但是在此之前我已经找到了别人提供的 api 了
<ul>
<li>
<strong>发现这个 api 有时超时</strong>
, 又找到了 pixiv.cat, 做了后手, 保证解析
</li>
</ul>
</li>
<li>
<strong>下载会卡住</strong>
:
<ul>
<li>
同文件系统建立连接需要使用到线程池, node 默认的线程池大小为 4 条,
发出网络链接却不会用到, 所以查询很快, 但是下载很容易卡住, 详细可以看
<a
href="https://juejin.im/post/5b1e55cbe51d45067e6fcb84"
target="_blank"
rel="noopener"
>
什么东西会占线程池
</a>
,
<a
href="https://stackoverflow.com/questions/22644328/when-is-the-thread-pool-used"
target="_blank"
rel="noopener"
>
when is thread pool used
</a>
<ul>
<li>
使用下载队列的模式, 固定最大同时可以进行连接的数量为 4, 用 setTimeout
事件循环来判断是否处理完毕
</li>
<li>可以多加几个线程, 不过 windows 需要带参数启动, 我没试</li>
</ul>
</li>
</ul>
</li>
<li>
<strong>内存同步</strong>
: js 不会出现这个函数执行到一半跳到另一个函数上, 所以不用写信号量什么的
</li>
</ul>
<h3 id="错误提醒-日志打印">
<a href="#错误提醒-日志打印" class="headerlink" title="错误提醒, 日志打印"></a>
错误提醒, 日志打印
</h3>
<p>
为了查找出可能的 bug, 建立一个完善的错误打印机制是很有必要的, 使用了
<code>progress</code>
来检测下载进度,
<code>log4js</code>
打印日志, 同时每张图片的查询都会伴随一个图片的信息对象, 每个查询的结果都会保存在其中,
在最后提示出来
</p>
</div>
</article>
<div class="post-copyright">
<div class="post-copyright__author">
<span class="post-copyright-meta">文章作者:</span>
<span class="post-copyright-info"><a href="mailto:undefined"></a></span>
</div>
<div class="post-copyright__type">
<span class="post-copyright-meta">文章链接:</span>
<span class="post-copyright-info">
<a href="https://luckyray-fan.github.io/2020/02/02/nodejs-app-picpick/">
https://luckyray-fan.github.io/2020/02/02/nodejs-app-picpick/
</a>
</span>
</div>
<div class="post-copyright__notice">
<span class="post-copyright-meta">版权声明:</span>
<span class="post-copyright-info">
本博客所有文章除特别声明外,均采用
<a href="https://creativecommons.org/licenses/by-nc-sa/4.0/">CC BY-NC-SA 4.0</a>
许可协议。转载请注明来自
<a href="https://luckyray-fan.github.io">luckyray</a>
!
</span>
</div>
</div>
<div class="post-meta__tag-list"></div>
<nav id="pagination">
<div class="prev-post pull-left">
<a href="/2020/02/10/heckel-diff-algorithm-implemention/">
<i class="fa fa-chevron-left"></i>
<span>heckel-diff-algorithm-implemention</span>
</a>
</div>
<div class="next-post pull-right">
<a href="/2020/01/03/computer-network/">
<span>计算机网络</span>
<i class="fa fa-chevron-right"></i>
</a>
</div>
</nav>
</div>
</div>
<footer class="footer-bg" style="background-image: url(http://img.luckyray.cn/896653.jpg)">
<div class="layout" id="footer">
<div class="copyright">©2019 - 2020 By null</div>
<div class="framework-info">
<span>驱动 -</span>
<a href="#"><span>Hexo</span></a>
<span class="footer-separator">|</span>
<span>主题 -</span>
<a href="#"><span>diary</span></a>
</div>
</div>
</footer>
<i class="fa fa-arrow-up" id="go-up" aria-hidden="true"></i>
<script src="./hexo-history-main.js"></script>
<script src="https://cdn.jsdelivr.net/npm/animejs@latest/anime.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/jquery@latest/dist/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@fancyapps/fancybox@latest/dist/jquery.fancybox.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/velocity-animate@latest/velocity.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/velocity-ui-pack@latest/velocity.ui.min.js"></script>
<script src="https://luckyray-fan.github.io/js/utils.js?version=1.6.1"></script>
<script src="https://luckyray-fan.github.io/js/fancybox.js?version=1.6.1"></script>
<script src="https://luckyray-fan.github.io/js/sidebar.js?version=1.6.1"></script>
<script src="https://luckyray-fan.github.io/js/copy.js?version=1.6.1"></script>
<script src="https://luckyray-fan.github.io/js/fireworks.js?version=1.6.1"></script>
<script src="https://luckyray-fan.github.io/js/transition.js?version=1.6.1"></script>
<script src="https://luckyray-fan.github.io/js/scroll.js?version=1.6.1"></script>
<script src="https://luckyray-fan.github.io/js/head.js?version=1.6.1"></script>
<script>
if (/Android|webOS|iPhone|iPod|BlackBerry/i.test(navigator.userAgent)) {
$('#nav').addClass('is-mobile');
$('footer').addClass('is-mobile');
}
</script>
</body>
</html>