[Python] 파이썬 웹 크롤링 기초 2-1 : Scrapy
웹 크롤링이란 간단히 설명하면, 웹 페이지 내용을 긁어오는 행위를 뜻한다.
파이썬 웹 크롤링 라이브러리 Scrapy 는 (잘 알려진 다른 라이브러리인) Beautiful Soup 보다 다양하고 많은 기능을 제공하며 프레임워크 형태로 사용할 수 있다.
스크래피(Scrap + y) 라는 라이브러리 이름에서 알 수 있듯이 웹페이지에서 내용을 스크랩하는 기능을 제공한다.
1. 설치
(1) 리눅스(ex : 우분투) OS 사용하는 경우
sudo apt-get install libffi-dev libssl-dev (파이썬 가상환경 사용하는 경우, “workon [가상환경명]” 입력) pip install scrapy |
(2) 윈도우 OS 사용하는 경우
(파이썬 가상환경 사용하는 경우, “workon [가상환경명]” 입력) pip install scrapy |
2. 특징
프레임워크 형태로 Beautiful Soup 보다 다양하고 많은 기능을 제공한다.
파이프라인 : 어떤 데이터를 가져올 때 가공/필터링할 수 있는 기능을 제공한다.
로깅 : 데이터 처리 시 관련 로그를 쓸 수 있다.
이메일 : 어떤 데이터가 들어왔을 때 이메일 전송이 가능하다.
3. 라이브러리 문서
https://doc.scrapy.org/en/0.24/intro/tutorial.html
cmd 터미널에서 명령어를 실행하면 스크래피 프로젝트 경로가 출력된다.
ex) C:\Users\gendev\testproject
파이썬 IDE 프로그램인 파이참(PyCharm) 에서 해당 폴더를 열어보자.
참고로 파이참 커뮤니티 버전은 무료다.
좌측의 폴더트리를 보면 이미 구조가 갖춰져있는 프레임워크 형태임을 알 수 있다.
아이템 파일(items.py)은 데이터를 가져올 때 해당 데이터를 클래스 형태로 만들 수 있도록 한다.
파이프라인 파일(pipelines.py)은 데이터를 후처리/가공하거나 필터링하는 기능을 담당한다. 예를 들면 데이터를 데이터베이스에 반영하는 코드를 추가할 수 있다.
세팅 파일(settings.py)은 스크래피 스파이더라고 하는 메인 프로그램에 대한 설정을 담당한다. 대표적으로 파이프라인의 순서를 지정하거나, 봇 이름을 변경할 수 있다.
스파이더 폴더(spiders) 안에 실질적으로 스크랩할 내용을 프로그래밍하면 된다.
(1) 웹페이지 html 전체내용 가져오기
spiders 폴더 하위에 bb_spider.py 라는 파일을 새로 생성하자.
bb_spider.py
import scrapy class BBSpider(scrapy.Spider) : name = “bb” allowed_domains = [“it-archives.com”] start_urls = [ “http://it-archives.com/page/8/“, “http://it-archives.com/page/9/“ ] def parse(self, response): filename = response.url.split(“/”)[-2] + “.html” with open(filename, ‘wb’) as f: f.write(response.body) |
스파이더 이름은 bb로 정했기 때문에(name = “bb”), 터미널에서 명령어 “scrapy crawl bb”라고 입력하면 된다.
명령어 실행 후 좌측 파일트리를 닫았다 열면(새로고침하면) 8.html 과 9.html 파일이 생성되었을 것이다.
열어보면 요청한 주소에 해당하는 웹페이지 html 전체 내용이 다운로드되어 있을 것이다.
(2) 웹페이지 xpath 로 원하는 값 가져오기 (xpath 로 파싱하기)
대상 웹페이지 (http://it-archives.com/page/8/) 를 크롬이나 엣지 브라우저에서 개발자 도구(단축키 F12)를 열어 확인해보면, 아래와 같은 html 구조를 갖고 있다.
html의 각 엘리먼트는 xpath라고 불리우는 구조적 경로를 갖고 있는데, 이 xpath 를 알면 웹페이지의 내용을 파싱할 수 있다.
spiders 폴더 하위의 bb_spider.py 파일 내용을 수정하자.
bb_spider.py
import scrapy class BBSpider(scrapy.Spider) : name = “bb” allowed_domains = [“it-archives.com”] start_urls = [ “http://it-archives.com/page/8/“, “http://it-archives.com/page/9/“ ] def parse(self, response): for sel in response.xpath(‘//article’): title = sel.xpath(‘header/h3/a/text()’).extract() link = sel.xpath(‘header/h3/a/@href’).extract() desc = sel.xpath(‘header/div/a/time/text()’).extract() print (title, link, desc) |
터미널에서 명령어 “scrapy crawl bb”라고 입력하면 아래와 같은 결과가 나온다.
(3) 웹페이지 파싱결과를 스크래피 아이템 객체에 담기
spiders 폴더 하위의 bb_spider.py 파일 내용을 수정하자.
bb_spider.py
import scrapy from testproject.items import BBItem class BBSpider(scrapy.Spider) : name = “bb” allowed_domains = [“it-archives.com”] start_urls = [ “http://it-archives.com/page/8/“, “http://it-archives.com/page/9/“ ] def parse(self, response): for sel in response.xpath(‘//article’): item = BBItem() item[‘title’] = sel.xpath(‘header/h3/a/text()’).extract() item[‘link’] = sel.xpath(‘header/h3/a/@href’).extract() item[‘desc’] = sel.xpath(‘header/div/a/time/text()’).extract() yield item |
이어서 items.py 파일 내용을 수정하자.
items.py
# Define here the models for your scraped items # # See documentation in: # https://docs.scrapy.org/en/latest/topics/items.html import scrapy class TestprojectItem(scrapy.Item): # define the fields for your item here like: # name = scrapy.Field() pass # 아이템 클래스 추가. scrapy.Item 를 상속받는다. class BBItem(scrapy.Item): title = scrapy.Field() link = scrapy.Field() desc = scrapy.Field() pass |
터미널에서 명령어 “scrapy crawl bb”라고 입력하면 아래와 같은 결과가 나온다.
print 함수를 따로 사용하지 않았지만 debug 로그를 통해 아이템 내용이 출력된다.
(4) 스크래피 아이템 객체에 저장된 내용을 결과파일 형태로 출력하기
이렇게 파싱한 결과를 파일로 저장하고 싶다면, 코드 내용은 그대로 두고 -o 옵션을 사용하면 된다.
scrapy crawl bb -o items.json 명령어를 사용하면 아래와 같이 json 파일이 결과파일로 떨어진다.
결과 json 파일을 다른 원하는 곳으로 보내서 가공하는 방법도 있고, pipelines.py 파일을 수정해서 데이터를 후처리할 수도 있다. 예를 들면 원하는 데이터를 DB에 반영하는 코드를 추가할 수 있다.
4-2. 스크래피 쉘 예제
프로젝트를 만들지 않고 대화형 쉘을 사용해서 스크래피 기능을 실행할 수 있다.
먼저 cmd 터미널에서 scrapy shell “http://it-archives.com/page/8/” 명령어를 실행해본다.
쉘이 실행되면 response.xpath(‘//title’) 이라고 입력하면 타이틀 태그를 가져온다.
=> [<Selector xpath=’//title’ data='<title>흑곰의 유익한 블로그 2호점 – 페이지 8 – 당신의 …’>]
이때 “//”는 모든 요소를 다 가져오기 한다는 의미이다.
결과는 list 형태로 반환된다.
# a 태그를 다 가져오기
response.xpath(‘//a’)
=> [<Selector xpath=’//a’ data='<a class=”skip-link screen-reader-tex…’>, <Selector xpath=’//a’ data='<a href=”http://it-archives.com/” rel…’>, <Selector xpath=’//a’ data='<a href=”#content” class=”menu-scroll…’>, <Selector xpath=’//a’ data='<a href=”http://it-archives.com/22163…‘>, <Selector xpath=’//a’ data='<a href=”http://it-archives.com/22163…‘>, <Selector xpath=’//a’ data='<a href=”http://it-archives.com/22163…‘>, <Selector xpath=’//a’ data='<a href=”http://it-archives.com/22163…‘>, (중략)
# 값을 가져올 때는 extract() 함수 사용
response.xpath(‘//title’).extract()
=> [‘<title>흑곰의 유익한 블로그 2호점 – 페이지 8 – 당신의 업무력 향상과 칼퇴를 돕는 블로그</title>’]
response.xpath(‘//title/text()’)
=> [<Selector xpath=’//title/text()’ data=’흑곰의 유익한 블로그 2호점 – 페이지 8 – 당신의 업무력 향상과…’>]
response.xpath(‘//title/text()’).extract()
=> [‘흑곰의 유익한 블로그 2호점 – 페이지 8 – 당신의 업무력 향상과 칼퇴를 돕는 블로그’]
# 정규표현식 사용하려면 re 함수 사용
# 정규표현식으로 단어별로 가져오기
response.xpath(‘//title/text()’).re(‘(\w+)’)
=> [‘흑곰의’, ‘유익한’, ‘블로그’, ‘2호점’, ‘페이지’, ‘8’, ‘당신의’, ‘업무력’, ‘향상과’, ‘칼퇴를’, ‘돕는’, ‘블로그’]
5. 활용
크롤러/크롤링 프로그램은 주기적으로 실행하고 싶은 경우.
리눅스(ex : 우분투) OS를 사용한다면 “crontab” 을 활용하면 되고, 윈도우 OS를 사용한다면 “작업 스케줄러” 를 활용하면 된다.
자세한 내용은 검색을 통해 해결하자.
다음글
https://blog.naver.com/bb_/222620363771

관련글
https://blog.naver.com/bb_/222619333734
