Scrapy 웹 크롤링 01 - 환경설정 및 기초

Scrapy VS Beautiful Soup

Beautiful Soup

  • Beautiful Soup는 웹 상의 정보를 빠르게 크롤링 하기위한 도구이며, 정적인 정보를 가져 올 수 있다. 즉, 해당 API(URL)에 요청했을때 바로 가져올수 있는 정보들만 가져올 수 있다. 시간이 좀 더 걸린 후에 나오는 정보들은 가져올 수 없다는 것이다. 진입 장벽이 매우 낮고 간결해서, 입문 개발자에게 안성맞춤이다. 그리고 이 라이브러리는 스스로 크롤링을 하는 것이 아니라 urlib2 또는 requests 모듈을 통해 HTML 소스를 가져와야 한다.

Scrapy

  • Scrapy는 Python으로 작성된 Framework이며, spider(bot)을 작성해서 크롤링을 한다. Scrapy에서는 직접 Beautiful Soup 이나 lxml을 사용할 수 있다. 하지만 Beautiful Soup에서는 지원하지 않는 Xpath를 사용할 수 있다. 또한, Xpath를 사용함으롴써 복잡한 HTML소스를 쉽게 크롤링 할 수 있게 해준다. 또한 Xpath를 통한 crawling이 가능한 모듈로는 selenium도 존재한다. selenium도 Scrapy와 연동해서 가능하다.

Anaconda env

  • 먼저 사전에 anaconda를 통해 가상환경을을 만들어준다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# env 생성
conda create -n env_name python=3.5

# env 리스트 보기
conda env list

# env 활성화
conda activate env_name

# env 비활성화
conda deavtivate

# env 삭제
conda env remove -n env_name

Scrapy 환경설정

  • 먼저 가상환경을 활성화시켜준 후에, spider bot을 만들 폴더의 상위 폴더에서 다음의 명령어를 실행시켜준다.
1
2
3
4
5
conda activate env_name

cd ..

scrapy startproject project_name
  • 다음과 같이 설정한 project명을 갖는 폴더가 만들어지며, 필자는 section01_2라고 명명했다.

create project folder

  • 위의 단계까지 실행했다면, 다음과 같은 출력이 보일 것이다. 빨간줄 아래에 나와있는 예시 명령어를 따라서 실행시키면 spider bot을 만들수 있다.

scrapy startproject

  • 또한, 모든 앞으로의 모든 명령어는 scrapy.cfg라는 파일이 존재하는 directory path에서 해야한다.

scrapy 명령어 실행하는 path

genspider

  • scrapy에서 가장 중요한 spider class를 만들어준다.
1
2
3
4
5
6
7
8
9
# spider를 만들기 위해 명령어를 실행하려면 scrapy.cfg파일의 경로로 이동해야하기 때문에
cd section01_2

# scrapy.cfg파일이 존재하는지 다시 한번 확인
ls

# https://blog.scrapinghub.com/은 crawling 테스트를 위한 사이트로 유명하다.
# https://blog.scrapinghub.com/이라는 사이트를 크롤링할 testspider라는 이름으로 spider 을 만들어라는 명령어
scrapy genspider testspider blog.scrapinghub.com
  • 다음과 같은 출력결과를 볼 수 있으며, section01_2에 spiders라는 폴더의 testspider라고 만들어졌다는 것을 의미한다.
    genspider

genspider 실행 후 파일 변경

1
2
3
4
5
6
7
8
# 만들어진 spider 파일 확일을 위해 이동
cd section01_2/spiders

# 위에서 만들어 놓았던 testspider라는 spider가 있는지 확인
ls

# testspider.py 확인
vim testspider.py

만들어진 spider 파일 확인

  • 먼저 straturl과 우리가 크롤링하려는 URL endpoint가 https인지 확인한 후 고쳐준다.(여기서 필자는 vim으로 수정하였기에 pep8에 의거하여 space 4번으로 indent를 사용하였다. space와 tap을 번갈아가며 사용하면 python interpreter가 다르게 인식하므로 에러를 발생시킨다!)

  • 앞으로의 실습에 헷갈림을 방지하기 위해서 name을 test1으로 변동해주었고, allowed_domains과 start_urls를 보면 설정해 놓은 대로 들어가 있는 것을 알 수 있다. 여기서 scrapy는 allowed_domains과 start_urls가 리스트 구조로 되어있는데 다른 URL과 도메인들을 추가하면 해당 사이트들을 돌아가며 크롤링을 할 수 있는 병렬처리가 가능하다는 것이 가장 큰 장점이다. 추후에 설명하겠지만, 눈치 빠르신 분들은 아래 parse함수에서 response를 parameter로 받는 함수이므로 이 함수에 크롤링하고 싶은 부분에 대한 코드를 만들면 크롤링이 가능하다는 것을 알 것이다!! 혹시 response에서 어떤 명령어가 사용가능한지 보고 싶다면

크롤링 상태 확인을 하기 위해 parse에 print문 추가

runspider vs crawl

  • runspider와 crawl의 차이점은 runspider는 spiders폴더에서 실행할 수 있고, crawl은 scrapy.cfg파일이 존재하는 폴더에서 실행하여햐 한다는 점이 차이점이다!! runspider 명령어를 통해 spider bot을 실행시키는 것은 단위 테스트라고 소위 불리는 방식을 할 때 유용하고 crawl은 우리가 원하는 구조를 다 만들어 놓은 후 테스트를 할 때나 실제로 크롤링을 할 경우 사용하는 것이 유용하다.
1
2
3
4
5
# runspider는 spiders 폴더에서 실행하여야한다.
scrapy runspider testspider.py

# crawl은 scrapy.cfg파일이 존재하는 path에서 실행시켜주어야한다.
scrapy crawl test1 --nolog

spider 실행후 결과 중 parse함수에서 reponse뒤에 사용할 수 있는 명령어의 종류

settings.py

settings.py의 위치

  • spider의 속성에 관련된 parameter들이 있는 파일이라고 생각하면 된다. 예를 들면, 아래의 그림에서 볼 수 있듯이 SPIDER MODULES는 현재 SPIDER의 위치를 의미하고, NEWSPIDER MODULE은 Spider를 새로 생성시 어느 위치에 추가되는지를 의미한다. ROBOTSTXT_OBEY는 robots.txt의 규칙에 의거하여 crawling을 하겠다는 의미이며, DOWNLOAD_DELAY는 몇초간격으로 서버에 요청을 할지에 대한 수치이다. 필자는 1로 정했는데 여기서는 1초마다라는 의미이다. 만약에 0.2라고 하게 되면 0.2초마다 서버에 요청하게 되어 서버에 부하를 일으키게 되면 심할경우 영구 van을 당할 수도 있기에 간격을 1초이상으로 하는 것을 권장한다.

settings.py

실습)blog.scrapinghub.com에서 기사 제목들만 크롤링 하기!

  • 위의 실습주제로 실습을 진행하기 위해서는 앞서 만들어본 spider 파일에서 parse함수를 수정해야할 것이다. 그에 앞서 크롤링할 blog.scrapinghub.com의 제목에 해당하는 css path를 보면 전체 html의 body 부분에서 div element 중 class의 이름이 post-header인 부분에만 존재하는 것을 개발자 도구를 통해 알아내었다. 다른 부분에 동일한 element나 class명을 가질 수도 있으므로 find를 해보아야한다!

  • 다음과 같이 제목을 크롤링하기 위해 testspider.py을 수정해 주었다.

크롤링을 위한 testspider.py 수정

  • 참고로 결과를 파일로 저장할때 scrapy가 지원하는 파일 형식은 json, jsonlines, jl, csv, xml, marshal, pickle이다. 결과를 저장할때 동일한 파일명과 확장자명을 가진 파일이 이미 존재한다면 그 파일에 데이터를 추가해주므로 주의하자!
1
2
3
4
5
# 필자는 spider 폴더에서 실행함.
scrapy runspider testspider.py -o result.csv -t csv

# result 파일인 result.csv가 만들어진 것을 확인할 수 있다.
ls

Requests를 사용하여 페이지 순회하며 크롤링

  • 우리가 예를 들어 어떤 페이지내에서 여러 항목에 대해 해당 url로 이동 후 크롤링하고 다시 그 전 페이지로 돌아가서 다음 항목의 url로 이동 후 크롤링하는 이런 순회를 거쳐야하는 작업은 request나 selenium으로 하게되면 iterable한 코드를 통해 가능하게 되며, 그렇지 않다면, 동일한 구성을 지닌 페이지들이라면 함수를 여러번 실행하는 등의 multiprocessing을 통해 병렬처리를 따로 해주어여하는 불편함이 있다. 허나, scrapy는 코드 몇 줄로 가능하다.

  • 먼저 앞의 spider말고 새로운 spider를 만들어 사용할 것이다. spider를 만든 설정은 위에서 만든 것과 동일하다. spider 이름만 pagerutine이라고 명명했을 뿐이다.

새로운 spider 만들기

  • 이전에 blog.scrapinghub.com의 페이지에 해당 10개의 기사들에 대한 path가 “div.post-header h2 > a” 이며, a tag의 href 속성 값들을 통해 각각의 기사에 해당 페이지로 이동이 가능할 수 있다는 사실을 확인 할 수 있다.

  • 첫번째 parse 함수에서 미리 추출한 url을 request하여 얻은 response를 다른 함수로 전달해주기 위해 Request 명령어를 사용하였으며, urljoin을 사용한 이유는 절대주소가 아닌 상대주소로 되어있는 경우 위의 start_urls에 설정해 놓은 주소를 앞에 붙여 절대 주소로 바꿔주는 기능이다. 물론 절대주소인 경우는 이런 작업을 생략한다.

pagerutine.py 파일

Scrapy Shell 사용법

  • 쉽게 말해 이전에 크롤링을 할때 Spider 폴더에서 파일을 수정하고 테스트해보는 방식으로는 작업의 효율성이 떨어지므로 그 전에 css나 xpath selector를 테스트해볼 수 있는 것이 Shell mode이다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# shell 모드 접속
scrapy shell

################ shell 모드 접속했다고 가정 ###############
# url 설정(request하는 대상을 바꾸는 역할)
fetch('url')

quit

################# 다른 방법 ############################

# 위의 단계를 한번에 하는 방법
scrapy shell https://blog.scrapinghub.com

# response data가 무엇이 있는지 확인 할 수 있다. 소스페이지를 현재 내 컴퓨저에 가져와서 보여주는 방식
view(response)

# 예시
fetch(https://daum.net)
view(response)

# response가 사용할수있는 method 확인
dir(response)

# 현재 reponse의 url 확인
response.url

# 현재 response의 body정보 확인
response.body

# 현재 reponse의 status 확인
response.status

# robot.txt에 크롤링이 허용되지 않았으면 shell script가 실행되지 않는다.
# settings 파일에서의 설정 파라미터들을 동적으로 설정하며 실행 가능!
scrapy shell https://daum.net --set="ROBOTSTXT_OBEY=False"