ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Parsing] Scrapy를 활용하여 웹 스크래핑 하기
    Project 2023. 7. 9. 00:44
    728x90

    Pyspider를 활용하여 크롤러를 구현해보려고 했으나, 왜 예시가 없나 했더니 코드도 구식이고 지금 시점에서 구현이 어려웠다...(공식문서에 자랑(?)했던 WebUI도 이제 지원하지 않는 듯) 그래서 대체재를 찾던 도중 Scrapy가 눈에 띄어 이것을 활용하여 만들어보기로 한다.

    +) 6년 전에 마지막으로 깃헙에 커밋된 코드라서, 자잘한 오류만 짚고 넘어가자면 gcd(최대공약수)를 구현하는데 math가 아닌 현재 지원하지 않는 fractions 모듈을 사용한다던가, 무차별적인 six 모듈에서 함수를 가져와 일일이 코드를 고치는 데 애를 먹기도 했고, pickle error가 자주 발생하기도 했다... 또한 인용하거나 따라해볼만한 튜토리얼 같은 문서가 부족하다

    Scrapy?

    https://keyhyuk-kim.medium.com/python-%EC%9B%B9-%ED%81%AC%EB%A1%A4%EB%9F%AC-%EB%8F%84%EA%B5%AC-%EB%B9%84%EA%B5%90-%EB%B0%8F-%EC%82%AC%EC%9A%A9-%ED%9B%84%EA%B8%B0-scrapy-vs-selenium-vs-requests-urllib-6483041ca1ba

     

    Python 웹 크롤러 도구 비교 및 사용 후기(Scrapy vs selenium vs Requests, urllib)

    웹 크롤러 개발 언어로 Python을 선택했다면, 개발 효율성을 높혀줄 여러가지 라이브러리와 프레임워크가 있습니다.

    keyhyuk-kim.medium.com

    Keyhyuk Kim 님의 블로그를 인용해보자면, Scrapy는 크롤링을 위해 만들어진 프레임워크다. 아래 사진에서도 알 수 있듯이, Scrapy는 미들웨어, 파이프라인, javascript renderer, proxy, xpath, CLI 등 다양한 기능과 플러그인들을 사용할 수 있다. 또한 병렬처리와 robots.txt(웹 페이지 내 데이터의 크롤링 허용 여부 표시) 준수 여부, 다운로드 설정 제어도 세부적으로 조정이 가능하다. (여기까지 구현하진 않았...)

    Scrapy의 공식문서는 다음과 같다.

    https://docs.scrapy.org/en/latest/

     

    Scrapy 2.9 documentation — Scrapy 2.9.0 documentation

    © Copyright 2008–2023, Scrapy developers. Revision 52c07264. Last updated on May 08, 2023.

    docs.scrapy.org

    위 링크를 들어가 보면 알겠지만, Scrapy는 Pyspider와 달리 많은 사람들이 이용하고 있는 오픈 소스다. 따라서 오류가 발생하더라도 참고해볼만한 자료가 구글에 많다. 

    Architecture

    공식 문서에 있는 Scrapy의 데이터 흐름을 보여주는 그림이다. 앞선 pyspider와 다른 양상을 보여주고 있다.

    1. Engine은 Spider로부터 크롤링하기 위해 첫 Req를 받는다

    2. Engine은 Scheduler 내에 Req들을 조정하고 크롤링하기 위한 다음 Req들을 요청한다.

    3. Scheduler는 Engine에게 다음 Req을 전달한다

    4. Engine은 Downloader Middleware를 경유하여 Downloader에게 Req을 보낸다.

    5. 페이지의 다운로드가 끝나면 Downloader는 Res를 만들고 Downloader middleware를 통해 Engine에게 전달한다.

    6. Engine은 Downloader로부터 Res를 받고 Spider에게 처리를 위해 Res를 전달한다(마찬가지로 middleware 경유)

    7. Spider는 Res를 처리하고 스크랩된 items와 새 Req을 Engine에게 전달한다.(middleware 경유)

    8. Engine은 처리된 item들을 Item Pipeline에 보낸다. 그리고 처리된 Req들을 Scheduler에게 보낸후 가능한 다음 Req들을 크롤링하기 위해 다시 요청한다.

    9. 3번부터의 일련의 과정을 Scheduler 내 Req이 없을 때까지 반복한다

    본인 깃헙 파일에 올려놓은 scrapy 폴더의 구조다. 한식을 주제로 스크랩하였고, json 파일 형식으로 저장하는 것을 목표로 하였다.

    대표 코드는 다음과 같다.

    import scrapy
    
    class KoreanfoodSpider(scrapy.Spider):
    	name = 'koreanfood'
    	start_urls = ["--탐색하고자 하는 웹 사이트--"]
    
    	def parse(self, response):
    		titles = response.xpath('//*[@id="content1"]/하위경로/text()').extract()
    		locations = response.xpath('//*[@id="content2"]/하위경로/text()').extract()
    		scores = response.xpath('//*[@id="content3"]/하위경로/text()').extract()
    
    		for item in zip(titles, locations, scores):
    			scraped_info = {
    				'title' : item[0].strip(),
    				'loc' : item[1].strip(),
    				'score' : item[2].strip(),
    			}
    			yield scraped_info

    이런 방식으로 scrapy를 활용하여 가져오고자 하는 HTML 문을 파싱할 수 있다. (css selector를 사용하지 않은 코드)

    또한 spider 폴더 내 settings.py 파일에 환경변수 FEED_FORMAT, FEED_URI를 추가하면 데이터 저장 파일의 형식과 파일 이름을 지정해줄 수 있다.

    # spider/settings.py
    
    # Scrapy settings for naverscraper project
    #
    # For simplicity, this file contains only settings considered important or
    # commonly used. You can find more settings consulting the documentation:
    #
    #     https://docs.scrapy.org/en/latest/topics/settings.html
    #     https://docs.scrapy.org/en/latest/topics/downloader-middleware.html
    #     https://docs.scrapy.org/en/latest/topics/spider-middleware.html
    
    BOT_NAME = "naverscraper"
    
    SPIDER_MODULES = ["naverscraper.spiders"]
    NEWSPIDER_MODULE = "naverscraper.spiders"
    
    
    # Crawl responsibly by identifying yourself (and your website) on the user-agent
    #USER_AGENT = "naverscraper (+http://www.yourdomain.com)"
    
    # Obey robots.txt rules
    ROBOTSTXT_OBEY = True
    
    # Configure maximum concurrent requests performed by Scrapy (default: 16)
    #CONCURRENT_REQUESTS = 32
    
    # Configure a delay for requests for the same website (default: 0)
    # See https://docs.scrapy.org/en/latest/topics/settings.html#download-delay
    # See also autothrottle settings and docs
    #DOWNLOAD_DELAY = 3
    # The download delay setting will honor only one of:
    #CONCURRENT_REQUESTS_PER_DOMAIN = 16
    #CONCURRENT_REQUESTS_PER_IP = 16
    
    # Disable cookies (enabled by default)
    #COOKIES_ENABLED = False
    
    # Disable Telnet Console (enabled by default)
    #TELNETCONSOLE_ENABLED = False
    
    # Override the default request headers:
    #DEFAULT_REQUEST_HEADERS = {
    #    "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
    #    "Accept-Language": "en",
    #}
    
    # Enable or disable spider middlewares
    # See https://docs.scrapy.org/en/latest/topics/spider-middleware.html
    #SPIDER_MIDDLEWARES = {
    #    "naverscraper.middlewares.NaverscraperSpiderMiddleware": 543,
    #}
    
    # Enable or disable downloader middlewares
    # See https://docs.scrapy.org/en/latest/topics/downloader-middleware.html
    #DOWNLOADER_MIDDLEWARES = {
    #    "naverscraper.middlewares.NaverscraperDownloaderMiddleware": 543,
    #}
    
    # Enable or disable extensions
    # See https://docs.scrapy.org/en/latest/topics/extensions.html
    #EXTENSIONS = {
    #    "scrapy.extensions.telnet.TelnetConsole": None,
    #}
    
    # Configure item pipelines
    # See https://docs.scrapy.org/en/latest/topics/item-pipeline.html
    #ITEM_PIPELINES = {
    #    "naverscraper.pipelines.NaverscraperPipeline": 300,
    #}
    
    # Enable and configure the AutoThrottle extension (disabled by default)
    # See https://docs.scrapy.org/en/latest/topics/autothrottle.html
    #AUTOTHROTTLE_ENABLED = True
    # The initial download delay
    #AUTOTHROTTLE_START_DELAY = 5
    # The maximum download delay to be set in case of high latencies
    #AUTOTHROTTLE_MAX_DELAY = 60
    # The average number of requests Scrapy should be sending in parallel to
    # each remote server
    #AUTOTHROTTLE_TARGET_CONCURRENCY = 1.0
    # Enable showing throttling stats for every response received:
    #AUTOTHROTTLE_DEBUG = False
    
    # Enable and configure HTTP caching (disabled by default)
    # See https://docs.scrapy.org/en/latest/topics/downloader-middleware.html#httpcache-middleware-settings
    #HTTPCACHE_ENABLED = True
    #HTTPCACHE_EXPIRATION_SECS = 0
    #HTTPCACHE_DIR = "httpcache"
    #HTTPCACHE_IGNORE_HTTP_CODES = []
    #HTTPCACHE_STORAGE = "scrapy.extensions.httpcache.FilesystemCacheStorage"
    
    # Set settings whose default value is deprecated to a future-proof value
    REQUEST_FINGERPRINTER_IMPLEMENTATION = "2.7"
    TWISTED_REACTOR = "twisted.internet.asyncioreactor.AsyncioSelectorReactor"
    FEED_EXPORT_ENCODING = "utf-8"
    FEED_FORMAT = "json"
    FEED_URI = "koreanfoods.json"

    *l0o02 님의 깃헙 블로그를 참고하여 작성한 포스트입니다.

    https://l0o02.github.io/2018/06/19/python-scrapy-1/

     

    파이썬 크롤링 튜토리얼 - 8 : Scrapy 사용법, 네이버 뉴스 크롤링해서 CSV로 내보내기 | 개발새발 블

    Scrapy Shell 을 통해 개념을 이해하고, 네이버 뉴스 페이지를 크롤링 하여 CSV파일로 내보내기까지 하겠습니다.

    l0o02.github.io

     

    728x90

    'Project' 카테고리의 다른 글

    웹 크롤러 설계  (0) 2023.07.12
    PySpider  (0) 2023.07.08
    웹 크롤링 데이터를 MySQL에 저장하기  (0) 2023.07.03
    Requests 알아보기  (0) 2023.06.28
    Client와 Server, REST API, JSON  (0) 2023.06.26
Designed by Tistory.