이번 게시글에서는 Scrapy를 파이썬 스크립트에서 어떻게 호출하고 사용하는지에 대해 소개하려 한다.
Scrapy는 프레임워크이기 때문에 쉘에서 사용하는 것이 일반적이지만, 필자는 서버에서 사용해야 하기 때문에 파이썬 스크립트에서 활용하였다.
튜토리얼은 네이버 블로그 검색 결과를 가져오는 방법을 소개한다.
Scrapy 튜토리얼3 - 네이버 검색 결과 크롤링(데이터 추출)
1. 설치
우선 Scrapy를 사용하기 위해 파이썬 프로젝트에 설치해보자
pip install Scrapy
2. Spider 클래스 생성
설치가 완료되었다면 우선 Spider라는 것을 만들어야 한다. 용어가 조금 생소한데, 거미줄을 쳐서 html에서 원하는 정보만 걸러 가져온다.. 라는 발상에서 나온 용어이지 않나 싶다.
Scrapy는 이 Spider라는 클래스를 호출해 크롤링을 실행한다.
필자는 크롤링을 실제로 진행하는 함수들을 모아둔 클래스 정도로 이해했다.
import scrapy
class NaverSpider(scrapy.Spider):
name = "naver"
# 처음 크롤링을 시작하는 함수
def start_requests(self):
# '강남 맛집'으로 검색한 네이버 블로그 결과 링크
url = "https://search.naver.com/search.naver?query=강남 맛집&nso=&where=blog&sm=tab_opt"
yield scrapy.Request(url=url, callback=self.parse)
# 크롤링 결과를 받는 callback함수
def parse(self, response):
# 해당 코드는 다음 게시물에서 설명합니다
result = response.css('.api_txt_lines').get()
print(result)
spider 클래스를 만드는 것에는 몇 가지 제약 조건이 있다.
1. 클래스는 scrapy.Spider를 상속받아야 한다.
클래스명은 어떤 것이든 관계 없다.
2. 클래스 멤버변수 name을 생성한다.
Scrapy가 spider를 사용하여 크롤링을 시작할 때, spider를 구분하기 위해 name 멤버변수를 사용한다.
name은 말 그대로 spider를 식별할 수 있는 이름으로 어떤 이름을 사용하든 상관없다.
3. start_requests(self)를 생성한다.
Scrapy는 이 start_requests 함수를 가장 먼저 호출한다. 함수명은 변경하면 안된다.
함수 안에는 반드시 'yield scrapy.Request(url=링크, callback=콜백함수)'가 선언되어 있어야한다.
return을 쓰면 TypeError: 'Request' object is not iterable 라는 에러가 발생한다.
(yield은 return과 달리 여러번 결과를 반환할 수 있다.)
yield로 인해 scrapy는 해당 링크로 요청을 보내고 콜백함수를 호출해 응답을 사용할 수 있도록 한다.
for문을 통해 여러개의 링크로 request를 보낼수도 있다.
#예시코드
class NaverSpider(scrapy.Spider):
name = "naver"
def start_requests(self):
urls = [링크1, 링크2, 링크3]
for url in urls :
yield scrapy.Request(url=url, callback=self.parse)
4. scrapy.Request의 콜백함수를 만든다.
콜백함수의 함수명은 어떤것이든 관계 없다. 그러나 매개변수로 response는 반드시 들어가있어야 한다.
scrapy가 콜백함수로 response를 보내주기 때문이다.
3. CrawlerProcess 호출
spider를 만들었다면 이제 scrapy에서 spider를 호출해야한다.
파이썬 스크립트에서 scrapy를 사용하는 방법은 2가지이다.
- CrawlerRunner()
- CrawlerProcess()
두 함수의 차이는 호출 방식도 있지만 메인 스레드가 아닌 다른 스레드에서 호출이 가능하냐 아니냐의 차이이다.
CrawlerRunner는 메인 스레드가 아닌 서브스레드, 서브 프로세스에서도 동작이 가능하다.
CrawlerProcess는 오직 메인 스레드에서만 동작이 가능하다.
CrawlerRunner는 여러개의 spider를 동시에 실행할 수 있다는 장점도 있다.
두 함수의 호출 방식을 살펴보자.
from scrapy.crawler import CrawlerRunner
if __name__ == '__main__':
configure_logging({'LOG_FORMAT': '%(levelname)s: %(message)s'})
runner = CrawlerRunner()
runner.crawl(NaverSpider) # 이 부분에 자신이 정의한 spider 클래스를 넣는다
# runner.crawl(DaumSpider) # 여러개의 spider를 동시에 실행할 수도 있다.
crawler = runner.join()
crawler.addBoth(lambda _: reactor.stop())
reactor.run() # the script will block here until the crawling is finished
위 코드는 공식문서 튜토리얼 코드 그대로이다. 필자도 특별히 이 부분에 대해 건드린 것은 없다.
reactor.run()이 실행되면 크롤링이 모두 끝날때까지 다음 코드로 이동하지 않고 기다려준다.
단 주의해야할 사항은 reactor는 한번 실행되면 해당 프로세스가 끝날때까지 재실행이 불가능하다.
from scrapy.crawler import CrawlerProcess
if __name__ == '__main__' :
process = CrawlerProcess()
process.crawl(NaverSpider) # 이 부분에 자신이 정의한 spider 클래스를 넣는다
process.start()
CrawlerProcess는 호출 방식이 더 심플하다.
reactor와 달리 여러번 호출이 가능하고, process.start() 역시 크롤링이 다 끝날때까지 기다려준다.
다음 포스트에서는 크롤링하여 받아온 response에서 데이터를 추출하는 작업을 진행하도록 하겠다
'Python' 카테고리의 다른 글
[Locust] 서버 부하테스트 툴 Locust 튜토리얼 (0) | 2022.04.21 |
---|---|
[Scrapy] Scrapy 튜토리얼3 - 네이버 검색 결과 크롤링(데이터 추출) (0) | 2022.03.17 |
[Scrapy] Scrapy 튜토리얼1 - Scrapy를 선택한 이유 (0) | 2022.03.17 |
[Python] string to Json (Json.loads()) 파싱 문제 (0) | 2022.03.10 |
[셀레니움 Selenium] 네이버 검색결과 스크롤 크롤링 (0) | 2022.01.08 |