scrapy

1. Scrapy 개요

Scrapy는 크롤링/스크레이핑을 위한 파이썬 프레임워크로서 풍부한 기능들이 존재합니다.

  • 웹 페이지에서 링크 추출하기
  • robots.txt를 기반으로 허가된 페이지와 금지된 페이지 구분하기
  • XML 사이트맵 추출과 링크 추출하기
  • 도메인과 IP 주소마다 크롤링 시간 간격 조정하기
  • 여러 개의 크롤링 대상을 병렬 처리하기
  • 중복된 URL 크롤링하지 않기
  • 오류가 발생했을 때 특정 횟수만큼 재시도하기
  • 크롤러를 데몬으로 만들기와 잡 관리하기


2. Scrapy 설치 (window 환경)

Scrapy는 1.1 버전부터 파이썬 3을 지원하고 있으며, 여러 파이썬 패키지들을 기반으로 만들어졌습니다.

  • lxml : libxml2와 libxslt를 사용한 C 확장 라이브러리로서 효율적인 XML과 HTML 파서 역할을 수행
  • twisted : 이벤트 구동(Event Drive) 네트워크 프로그래밍 엔진을 기반으로 만들어졌기 떄문에 웹사이트 다운로드 처리를 비동기적으로 실행하며 다운로드 중에도 스크레이핑 처리 등을 할 수 있습니다.

공식 문서에 따르면 Scrapy를 설치 시 pip말고, Anaconda 또는 miniconda를 설치하여 conda-forge 채널의 패키지를 활용하는 것이 많은 설치 이슈를 피할 수 있다고 추천하고 있습니다. (Scrapy install guide)

conda install -c conda-forge scrapy

약 2~3분 정도의 시간이 소요되며 설치가 완료된 후에 scrapy --version 해당 명령어를 실행시키면 아래와 같은 결과를 보실 수 있습니다.

C:\Users>scrapy --version
Scrapy 1.5.1 - no active project

Usage:
  scrapy <command> [options] [args]

Available commands:
  bench         Run quick benchmark test
  fetch         Fetch a URL using the Scrapy downloader
  genspider     Generate new spider using pre-defined templates
  runspider     Run a self-contained spider (without creating a project)
  settings      Get settings values
  shell         Interactive scraping console
  startproject  Create new project
  version       Print Scrapy version
  view          Open URL in browser, as seen by Scrapy

  [ more ]      More commands available when run from project directory

Use "scrapy <command> -h" to see more info about a command


3. 공식 예제

1.5 버전의 공식 예제는 http://quotes.toscrape.com 사이트의 링크를 순회하며 text와 authon를 스크레이핑하는 코드입니다.

quotes_spider.py

import scrapy

class QuotesSpider(scrapy.Spider):
    # spider의 이름(변경가능)
    name = "quotes"
    # 크롤링을 시작할 URL 리스트
    start_urls = [
        'http://quotes.toscrape.com/tag/humor/',
    ]

    def parse(self, response):
        '''
        링크를 순회하며 div.quote부분의 text와 author를 추출
        '''
        for quote in response.css('div.quote'):
            yield {
                'text': quote.css('span.text::text').extract_first(),
                'author': quote.xpath('span/small/text()').extract_first(),
            }

        '''
        최상위 페이지의 모든 링크를 추출
        '''    
        next_page = response.css('li.next a::attr("href")').extract_first()
        if next_page is not None:
            yield response.follow(next_page, self.parse)

scrapy의 runspider 명령어의 파라미터로 [실행 파일 경로, 출력 형태]를 지정하여 실행하면 로그와 함께 크롤링이 완료된 것을 볼 수 있습니다.

scrapy runspider quotes_spider.py -o quotes.json


실행 결과

C:\workspace\python\scrapy>scrapy runspider quotes_spider.py -o quotes.json
2018-07-22 12:23:17 [scrapy.utils.log] INFO: Scrapy 1.5.1 started (bot: scrapybot)
2018-07-22 12:23:17 [scrapy.utils.log] INFO: Versions: lxml 3.6.4.0, libxml2 2.9.4, cssselect 1.0.3, parsel 1.4.0, w3lib 1.19.0, Twisted 17.5.0, Python 3.5.2 |Anaconda custom (64-bit)| (default, Jul  5 2016, 11:41:13) [MSC v.1900 64 bit (AMD64)], pyOpenSSL 16.2.0 (OpenSSL 1.0.2o  27 Mar 2018), cryptography 1.5, Platform Windows-10-10.0.17134-SP0
2018-07-22 12:23:17 [scrapy.crawler] INFO: Overridden settings: {'FEED_FORMAT': 'json', 'SPIDER_LOADER_WARN_ONLY': True, 'FEED_URI': 'quotes.json'}
2018-07-22 12:23:17 [scrapy.middleware] INFO: Enabled extensions:
...
2018-07-22 12:23:19 [scrapy.core.engine] DEBUG: Crawled (200) <GET http://quotes.toscrape.com/tag/humor/> (referer: None)
2018-07-22 12:23:20 [scrapy.core.scraper] DEBUG: Scraped from <200 http://quotes.toscrape.com/tag/humor/>
{'author': 'Jane Austen', 'text': '“The person, be it gentleman or lady, who has not pleasure in a good novel, must be intolerably stupid.”'}
...
'finish_time': datetime.datetime(2018, 7, 22, 3, 23, 20, 646076),
 'start_time': datetime.datetime(2018, 7, 22, 3, 23, 18, 724216)}
2018-07-22 12:23:20 [scrapy.core.engine] INFO: Spider closed (finished)


출력 결과 확인 

C:\workspace\python\scrapy>type quotes.json
[
{"text": "\u201cThe person, be it gentleman or lady, who has not pleasure in a good novel, must be intolerably stupid.\u201d", "author": "Jane Austen"},
...
{"text": "\u201cA lady's imagination is very rapid; it jumps from admiration to love, from love to matrimony in a moment.\u201d", "author": "Jane Austen"}
][
{"author": "Jane Austen", "text": "\u201cThe person, be it gentleman or lady, who has not pleasure in a good novel, must be intolerably stupid.\u201d"},
...
{"author": "Jane Austen", "text": "\u201cA lady's imagination is very rapid; it jumps from admiration to love, from love to matrimony in a moment.\u201d"}
]



Reference

  • Scrapy 1.5 documentation
  • 카토 코다, 『파이썬을 이용한 웹 크롤링과 스크레이핑』, 윤인성, 위키북스(2018-03-22), p267~270.


+ Recent posts