요즘 웹 크롤링은 잘 알려진 기술이지만 여전히 복잡한 부분이 많습니다. 단순한 웹 크롤러는 여전히 Ajax 회전 훈련, XMLHttpRequest, WebSockets, Flash Sockets 등과 같은 다양하고 복잡한 기술에 대처하기 어렵습니다. 웹사이트.
Hubdoc 프로젝트에 대한 기본 요구 사항을 예로 들어보겠습니다. 이 프로젝트에서는 청구 금액, 만기일, 계좌 번호, 그리고 가장 중요한 것은 다음과 같은 은행, 유틸리티 및 신용 카드 회사의 웹사이트에서 수집합니다. 최근 청구서 PDF. 이 프로젝트를 위해 나는 매우 간단한 솔루션(당분간 평가하고 있는 고가의 상용 제품을 사용하지 않음)으로 시작했습니다. 이는 MessageLab/Symantec에서 Perl을 사용하기 전에 수행했던 간단한 크롤러 프로젝트였습니다. 그러나 결과는 비참했습니다. 스패머는 은행이나 유틸리티 회사보다 훨씬 단순한 웹사이트를 만들었습니다.
그렇다면 이 문제를 어떻게 해결할 수 있을까요? 주로 Mikea가 개발한 우수한 request 라이브러리를 사용하여 시작했습니다. 브라우저에서 요청하고 네트워크 창에서 어떤 요청 헤더가 전송되었는지 확인한 다음 이러한 요청 헤더를 코드에 복사합니다. 과정은 간단합니다. 로그인부터 PDF 파일 다운로드까지의 프로세스를 추적한 다음 이 프로세스의 모든 요청을 시뮬레이션합니다. 비슷한 일을 더 쉽게 처리하고 웹 개발자가 더 합리적으로 크롤러 프로그램을 작성할 수 있도록 HTML에서 결과를 가져오는 방법을 jQuery(경량 cheerio 라이브러리 사용)로 내보냈습니다. 작업이 쉽고 CSS 선택기를 사용하여 페이지의 요소를 선택하는 것도 더 쉬워집니다. 전체 프로세스는 프레임워크로 래핑되며, 이 프레임워크는 데이터베이스에서 인증서 가져오기, 개별 로봇 로드, Socket.io를 통한 UI와의 통신 등의 추가 작업도 수행할 수 있습니다.
이것은 일부 웹사이트에서 작동하지만 이러한 회사가 사이트에 배치한 것은 내 node.js 코드가 아니라 JS 스크립트일 뿐입니다. 그들은 레거시 문제를 복잡성에 겹쳐서 로그인 정보 포인트를 얻기 위해 무엇을 해야 할지 파악하기가 매우 어렵습니다. request() 라이브러리와 결합하여 일부 사이트를 얻으려고 며칠 동안 시도했지만 여전히 헛된 것입니다.
충돌할 뻔한 후 node에서 phantomjs 헤드리스 웹킷 브라우저를 제어할 수 있는 라이브러리인 node-phantomjs를 발견했습니다(번역자 주: 이 기능이 없습니다). 여기서 해당 명사 headless를 생각하면 디스플레이 장치 없이 백그라운드에서 페이지 렌더링이 완료된다는 의미입니다. 이는 간단한 해결책처럼 보이지만 phantomjs에는 해결해야 할 피할 수 없는 문제가 여전히 있습니다.
1. PhantomJS는 페이지가 로드되었는지 여부만 알려줄 수 있으며, 그 과정에서 JavaScript나 메타 태그를 통한 리디렉션이 있는지 여부는 확인할 수 없습니다. 특히 JavaScript가 setTimeout()을 사용하여 호출을 지연시키는 경우.
2.PhantomJS는 위에서 언급한 문제를 처리할 수 있는 pageLoadStarted 후크를 제공하지만 이 기능은 로드할 페이지 수를 결정하고 각 페이지가 로드될 때만 사용할 수 있습니다. 숫자가 0으로 감소하면 콜백 함수가 호출되도록 가능한 시간 초과에 대한 처리를 제공합니다(항상 발생하는 것은 아니므로). 이 접근 방식은 효과가 있지만 항상 약간 해킹처럼 느껴집니다.
3. PhantomJS는 크롤링하는 각 페이지에 대해 완전히 독립적인 프로세스가 필요합니다. 그렇지 않으면 각 페이지 간의 쿠키를 분리할 수 없기 때문입니다. 동일한 phantomjs 프로세스를 사용하면 로그인된 페이지의 세션이 다른 페이지로 전송됩니다.
4. PhantomJS를 사용하여 리소스를 다운로드할 수 없습니다. 페이지를 png 또는 pdf로만 저장할 수 있습니다. 이는 유용하지만 PDF를 다운로드하려면 request()를 사용해야 함을 의미합니다.
5. 위의 이유로 인해 PhantomJS 세션에서 request() 세션 라이브러리로 쿠키를 배포하는 방법을 찾아야 합니다. document.cookie 문자열을 배포하고 구문 분석한 후 request() 쿠키 jar에 삽입하면 됩니다.
6. 브라우저 세션에 변수를 주입하는 것은 쉽지 않습니다. 이렇게 하려면 Javascript 함수를 생성하기 위한 문자열을 생성해야 합니다.
8. 일부 웹사이트는 항상 console.log()와 같은 코드로 가득 차 있어 재정의하여 원하는 위치에 출력해야 합니다. 이를 달성하기 위해 다음과 같이 합니다.
10. 또한 서버가 폭발하지 않도록 브라우저 세션의 최대 동시성을 제한해야 합니다. 그러나 이 한계는 값비싼 상용 솔루션이 제공할 수 있는 것보다 훨씬 높습니다. (역자 주: 상용 솔루션은 이 솔루션보다 동시성이 더 높습니다)
모든 작업이 완료되면 괜찮은 PhantomJS 요청 크롤러 솔루션을 갖게 됩니다. request() 요청으로 돌아가기 전에 PhantomJS를 사용하여 로그인해야 합니다. PhantomJS에 설정된 쿠키를 사용하여 로그인된 세션을 인증합니다. request()의 스트림을 사용하여 pdf 파일을 다운로드할 수 있기 때문에 이는 큰 승리입니다.
전체 계획은 웹 개발자가 jQuery 및 CSS 선택기를 사용하여 다양한 웹 사이트에 대한 크롤러를 만드는 방법을 비교적 쉽게 이해할 수 있도록 하는 것입니다. 아직 이 아이디어가 실현 가능하다는 것을 성공적으로 입증하지는 못했지만 곧 그렇게 될 것이라고 믿습니다. .