Node.js로 크롤러를 작성하고 Baidu 이미지_node.js를 크롤링하는 예를 공유하기 위한 기본 아이디어
其实写爬虫的思路十分简单:
- 按照一定的规律发送 HTTP 请求获得页面 HTML 源码(必要时需要加上一定的 HTTP 头信息,比如 cookie 或 referer 之类)
- 利用正则匹配或第三方模块解析 HTML 代码,提取有效数据
- 将数据持久化到数据库中
但是真正写起这个爬虫来,我还是遇到了很多的问题(和自己的基础不扎实也有很大的关系,node.js 并没有怎么认真的学过)。主要还是 node.js 的异步和回调知识没有完全掌握,导致在写代码的过程中走了很多弯路。
模块化
模块化对于 node.js 程序是至关重要的,不能像原来写 PHP 那样所有的代码都扔到一个文件里(当然这只是我个人的恶习),所以一开始就要分析这个爬虫需要实现的功能,并大致的划分了三个模块。
主程序,调用爬虫模块和持久化模块实现完整的爬虫功能
爬虫模块,根据传来的数据发送请求,解析 HTML 并提取有用数据,返回一个对象
持久化模块,接受一个对象,将其中的内容储存到数据库中
模块化也带来了困扰了我一个下午的问题:模块之间的异步调用导致数据错误。其实我至今都不太明白问题到底出在哪儿,鉴于脚本语言不那么方便的调试功能,暂时还没有深入研究。
另外一点需要注意的是,模块化时尽量慎用全局对象来储存数据,因为可能你这个模块的一个功能还没有结束,这个全局变量已经被修改了。
Control Flow
这个东西很难翻译,直译叫控制流(吗)。众所周知,node.js 的核心思想就是异步,但是异步多了就会产生好几层嵌套,代码实在难看。这个时候,你需要借助一些 Control Flow 模块来重新整理你的逻辑。在这里就要推荐开发社区十分活跃,用起来也很顺手的 async.js(https://github.com/caolan/async/)。
async 提供了很多实用的方法,我在写爬虫时主要用到了
- async.eachSeries(arr, fn, callback) 依次把 arr 中的每一个元素传给 fn,若 fn 回调没有返回错误对象就继续传下一个,否则把错误对象传给 callback,循环结束
- async.parallel(fn[, fn] , callback) 当所有的 fn 都执行完成后执行 callback
这些控制流方法给爬虫的开发工作带来了很大的方便。考虑这么一个应用场景,你需要把若干条数据插入数据库(属于同一个学生),你需要在所有数据都插入完成后才能返回结果,那么如何保证所有的插入操作都结束了呢?只能是层层回调保证,如果用 async.parallel 就方便多了。
这里再多提一句,本来保证所有的插入都完成这个操作可以在 SQL 层实现,即 transaction,但是 node-mysql 截止我使用的时候还是没有很好的支持 transaction,所以只有自己手动用代码保证了。
解析 HTML
在解析过程中也遇到一些问题,这里一并记录下来。
最基本的发送 HTTP 请求获得 HTML 代码,使用 node 自带的 http.request 功能即可。如果是爬简单的内容,比如获得某个指定 id 元素中的内容(常见于抓去商品价格),那么正则足以完成任务。但是对于复杂的页面,尤其是数据项较多的页面,使用 DOM 会更加方便高效。
而 node.js 最好的 DOM 实现非 cheerio(https://github.com/MatthewMueller/cheerio) 莫属了。其实 cheerio 应该算是 jQuery 的一个针对 DOM 操作优化和精简的子集,包含了 DOM 操作的大部分内容,去除了其它不必要的内容。使用 cheerio 你就可以像用普通 jQuery 选择器那样选择你需要的内容。
下载图片
在爬数据时,我们可能还需要下载图片。其实下载图片的方式和普通的网页没有太大的区别,但是有一点让我吃了苦头。
注意下面代码中言辞激烈的注释,那就是我年轻时犯下的错误……
var req = http.request(options, function(res){ //初始化数据!!! var binImage = ''; res.setEncoding('binary'); res.on('data', function(chunk){ binImage += chunk; }); res.on('end', function(){ if (!binImage) { console.log('image data is null'); return null; } fs.writeFile(imageFolder + filename, binImage, 'binary', function(err){ if (err) { console.log('image writing error:' + err.message); return null; } else{ console.log('image ' + filename + ' saved'); return filename; } }); }); res.on('error', function(e){ console.log('image downloading response error:' + e.message); return null; }); }); req.end();
GBK 转码
另外一个值得说明的问题就是 node.js 爬虫在爬 GBK 编码内容时转码的问题,其实这个问题很好解决,但是新手可能会绕弯路。这里就把源码全部奉上:
var req = http.request(options, function(res) { res.setEncoding('binary'); res.on('data', function (chunk) { html += chunk; }); res.on('end', function(){ //转换编码 html = iconv.decode(html, 'gbk'); }); }); req.end();
这里我使用的转码库是 iconv-lite(https://github.com/ashtuchkin/iconv-lite),完美支持 GBK 和 GB2312 等双字节编码。
实例:爬虫批量下载百度图片
var fs = require('fs'), path = require('path'), util = require('util'), // 以上为Nodejs自带依赖包 request = require('request'); // 需要npm install的包 // main函数,使用 node main执行即可 patchPreImg(); // 批量处理图片 function patchPreImg() { var tag1 = '摄影', tag2 = '国家地理', url = 'http://image.baidu.com/data/imgs?pn=%s&rn=60&p=channel&from=1&col=%s&tag=%s&sort=1&tag3=', url = util.format(url, 0, tag1, tag2), url = encodeURI(url), dir = 'D:/downloads/images/', dir = path.join(dir, tag1, tag2), dir = mkdirSync(dir); request(url, function(error, response, html) { var data = JSON.parse(html); if (data && Array.isArray(data.imgs)) { var imgs = data.imgs; imgs.forEach(function(img) { if (Object.getOwnPropertyNames(img).length > 0) { var desc = img.desc || ((img.owner && img.owner.userName) + img.column); desc += '(' + img.id + ')'; var downloadUrl = img.downloadUrl || img.objUrl; downloadImg(downloadUrl, dir, desc); } }); } }); } // 循环创建目录 function mkdirSync(dir) { var parts = dir.split(path.sep); for (var i = 1; i <= parts.length; i++) { dir = path.join.apply(null, parts.slice(0, i)); fs.existsSync(dir) || fs.mkdirSync(dir); } return dir; } var index = 1; // 开始下载图片,并log统计日志 function downloadImg(url, dir, desc) { var fileType = 'jpg'; if (url.match(/\.(\w+)$/)) fileType = RegExp.$1; desc += '.' + fileType; var options = { url: url, headers: { Host: 'f.hiphotos.baidu.com', Cookie: 'BAIDUID=810ACF57B5C38556045DFFA02C61A9F8:FG=1;' } }; var startTime = new Date().getTime(); request(options) .on('response', function() { var endTime = new Date().getTime(); console.log('Downloading...%s.. %s, 耗时: %ss', index++, desc, (endTime - startTime) / 1000); }) .pipe(fs.createWriteStream(path.join(dir, desc))); }

핫 AI 도구

Undresser.AI Undress
사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover
사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool
무료로 이미지를 벗다

Clothoff.io
AI 옷 제거제

AI Hentai Generator
AI Hentai를 무료로 생성하십시오.

인기 기사

뜨거운 도구

메모장++7.3.1
사용하기 쉬운 무료 코드 편집기

SublimeText3 중국어 버전
중국어 버전, 사용하기 매우 쉽습니다.

스튜디오 13.0.1 보내기
강력한 PHP 통합 개발 환경

드림위버 CS6
시각적 웹 개발 도구

SublimeText3 Mac 버전
신 수준의 코드 편집 소프트웨어(SublimeText3)

뜨거운 주제











얼굴 검출 및 인식 기술은 이미 상대적으로 성숙하고 널리 사용되는 기술입니다. 현재 가장 널리 사용되는 인터넷 응용 언어는 JS입니다. 웹 프런트엔드에서 얼굴 감지 및 인식을 구현하는 것은 백엔드 얼굴 인식에 비해 장점과 단점이 있습니다. 장점에는 네트워크 상호 작용 및 실시간 인식이 줄어 사용자 대기 시간이 크게 단축되고 사용자 경험이 향상된다는 단점이 있습니다. 모델 크기에 따라 제한되고 정확도도 제한됩니다. js를 사용하여 웹에서 얼굴 인식을 구현하는 방법은 무엇입니까? 웹에서 얼굴 인식을 구현하려면 JavaScript, HTML, CSS, WebRTC 등 관련 프로그래밍 언어 및 기술에 익숙해야 합니다. 동시에 관련 컴퓨터 비전 및 인공지능 기술도 마스터해야 합니다. 웹 측면의 디자인으로 인해 주목할 가치가 있습니다.

인터넷 금융의 급속한 발전으로 인해 주식 투자는 점점 더 많은 사람들의 선택이 되었습니다. 주식 거래에서 캔들 차트는 주가의 변화 추세를 보여주고 투자자가 보다 정확한 결정을 내리는 데 도움이 되는 일반적으로 사용되는 기술적 분석 방법입니다. 이 기사에서는 PHP와 JS의 개발 기술을 소개하고 독자가 주식 캔들 차트를 그리는 방법을 이해하도록 유도하며 구체적인 코드 예제를 제공합니다. 1. 주식 캔들 차트의 이해 주식 캔들 차트를 그리는 방법을 소개하기 전에 먼저 캔들 차트가 무엇인지부터 이해해야 합니다. 캔들스틱 차트는 일본인이 개발했습니다.

Pinetwork 노드에 대한 자세한 설명 및 설치 안내서이 기사에서는 Pinetwork Ecosystem을 자세히 소개합니다. Pi 노드, Pinetwork 생태계의 주요 역할을 수행하고 설치 및 구성을위한 전체 단계를 제공합니다. Pinetwork 블록 체인 테스트 네트워크가 출시 된 후, PI 노드는 다가오는 주요 네트워크 릴리스를 준비하여 테스트에 적극적으로 참여하는 많은 개척자들의 중요한 부분이되었습니다. 아직 Pinetwork를 모른다면 Picoin이 무엇인지 참조하십시오. 리스팅 가격은 얼마입니까? PI 사용, 광업 및 보안 분석. Pinetwork 란 무엇입니까? Pinetwork 프로젝트는 2019 년에 시작되었으며 독점적 인 Cryptocurrency Pi Coin을 소유하고 있습니다. 이 프로젝트는 모든 사람이 참여할 수있는 사람을 만드는 것을 목표로합니다.

JavaScript 튜토리얼: HTTP 상태 코드를 얻는 방법, 특정 코드 예제가 필요합니다. 서문: 웹 개발에서는 서버와의 데이터 상호 작용이 종종 포함됩니다. 서버와 통신할 때 반환된 HTTP 상태 코드를 가져와서 작업의 성공 여부를 확인하고 다양한 상태 코드에 따라 해당 처리를 수행해야 하는 경우가 많습니다. 이 기사에서는 JavaScript를 사용하여 HTTP 상태 코드를 얻는 방법과 몇 가지 실용적인 코드 예제를 제공합니다. XMLHttpRequest 사용

자바 크롤러 실습: 웹페이지 데이터를 효율적으로 크롤링하는 방법 소개: 인터넷의 급속한 발전으로 인해 다양한 웹페이지에는 수많은 귀중한 데이터가 저장되어 있습니다. 이 데이터를 얻으려면 각 웹 페이지에 수동으로 액세스하여 정보를 하나씩 추출해야 하는 경우가 많으며 이는 의심할 여지 없이 지루하고 시간이 많이 걸리는 작업입니다. 이 문제를 해결하기 위해 사람들은 다양한 크롤러 도구를 개발했으며 그중 Java 크롤러가 가장 일반적으로 사용되는 것 중 하나입니다. 이 기사에서는 독자들이 Java를 사용하여 효율적인 웹 크롤러를 작성하는 방법을 이해하고 특정 코드 예제를 통해 실습을 보여줄 것입니다. 1. 파충류의 기초

JavaScript에서 HTTP 상태 코드를 얻는 방법 소개: 프런트 엔드 개발에서 우리는 종종 백엔드 인터페이스와의 상호 작용을 처리해야 하며 HTTP 상태 코드는 매우 중요한 부분입니다. HTTP 상태 코드를 이해하고 얻는 것은 인터페이스에서 반환된 데이터를 더 잘 처리하는 데 도움이 됩니다. 이 기사에서는 JavaScript를 사용하여 HTTP 상태 코드를 얻는 방법을 소개하고 구체적인 코드 예제를 제공합니다. 1. HTTP 상태 코드란 무엇입니까? HTTP 상태 코드는 브라우저가 서버에 요청을 시작할 때 서비스가

js와 vue의 관계: 1. 웹 개발의 초석인 JS 2. 프론트엔드 프레임워크로서의 Vue.js의 등장 3. JS와 Vue의 상호 보완적인 관계 4. JS와 Vue의 실제 적용 Vue.

JS-Torch 소개 JS-Torch는 구문이 PyTorch와 매우 유사한 딥 러닝 JavaScript 라이브러리입니다. 여기에는 완전한 기능을 갖춘 텐서 객체(추적된 그라디언트와 함께 사용 가능), 딥 러닝 레이어 및 기능, 자동 미분 엔진이 포함되어 있습니다. JS-Torch는 JavaScript의 딥러닝 연구에 적합하며 딥러닝 개발을 가속화할 수 있는 다양한 편리한 도구와 기능을 제공합니다. Image PyTorch는 Meta 연구팀이 개발하고 유지 관리하는 오픈 소스 딥 러닝 프레임워크입니다. 신경망 모델을 구축하고 훈련하기 위한 풍부한 도구와 라이브러리 세트를 제공합니다. PyTorch는 간단하고 유연하며 사용하기 쉽게 설계되었으며 동적 계산 그래프 기능을 통해
