관리 메뉴

멍개의 연구소

크롤러 개발 라이브러리, 프레임워크 본문

서버/크롤러

크롤러 개발 라이브러리, 프레임워크

멍개. 2017. 5. 10. 08:44

크롤러는 주로 파이썬을 통해개발을 합니다.

javascript에서도 chreeio와 같이 크롤러를 할 수 있도록 해주는 라이브러리가 있으나, 비동기 적인 특성 때문에 코드의 작성이 상당히 어려운 부분이 있습니다. 

그래서 다양한 라이브러리 제공하는 파이썬을 많이 사용합니다.


크롤러는 크게 2종류의 모듈을 사용합니다. 


    1. 웹 페이지 요청하는 모듈

    2. 요청후 응답 받은 html 돔을 제어 할 수 있는 모듈(파서)


파이썬에서는 웹 페이지 요청을 하는 라이브러리로 requests와 urllib를 사용을 합니다. 

파서 모듈로 BeautifulSoup(bs4)를 사용합니다.


우선 requests와 urllib는 요청하는건 같은데 내부적으로 텍스트를 처리하는 방식, 에러를 처리하는 방식이 다릅니다.


urllib의 404 에러 처리하는 방법

1
2
3
4
5
6
7
8
9
10
from urllib.request import urlopen as rq
 
url = ''
try:
    page = rq(url)
    print(page.code)
    soup1 = BeautifulSoup(page, 'lxml')
 
except urllib.error.HTTPError:
    print('404 error')
cs



requests의 404 에러 처리하는 방법

1
2
3
4
5
6
7
8
9
10
11
import requests as rq
 
url = ''
 
page = rq(url)
res_code = page.code
    
soup1 = BeautifulSoup(page.text, 'lxml')
 
if(res_code == 404):
    print('404 error')
cs


urllib는 404를 except처리를 해버립니다.

왜 굳이 저렇게 했는지는 잘 모르겠는데... 저게 은근히 귀찮더군요


그리고 두 모듈을 텍스트 인코딩 방식도 다릅니다.

기본적으로 charset이 utf-8 방식은 크게 문제가 없는데, EUC-KR방식으로 인코딩이 된 사이트는 requests로 요청을 보내면 한글이 전부 깨지는 현상이 있습니다. 

이럴 땐 urllib를 사용하면 한글을 깨지지 않은 상태로 응답을 받게 됩니다. 


urllib가 requests모듈보다 좀더 로우단 모듈이기 때문에 에러 처리를 함에 있어서 좀더 신경을 써주어야 하는 단점이 있습니다.

덕분에 코드의 depth가 1~2개정도 더 들어갈 수 있습니다.


이렇게 요청을 보내서 응답을 받으면, 

파서를 통해 텍스트를 돔제어를 할 수 있도록 해주어야 합니다. 


bs4 라이브러리를 사용을 하게 됩니다.

근데 이게 쓰다보니 치명적인 버그가 있는데요....


bs4.BeautifulSoup은 두개의 인자를 받게 됩니다.

첫번째 인자로는 돔을 제어 할 텍스트, 즉 응답받은 텍스트를 넣으면 됩니다.

두번째 인자로는 파서를 넣게 되는데 가장 많이 쓰는것은 lxml, html5lib를 사용하게 됩니다.


이게 쓰다보니 lxml과 html5lib가 어떻게 파싱을 하는지는 잘 모르겠는데 두개 모두 군데군데 파서가 잘 안될때가 있습니다. 



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<ul class="u1">                                    
    <img src="/test_0.jpg" />1
    <img src="/test_1.jpg" />2
    <img src="/test_2.jpg" />3
    <img src="/test_3.jpg" />4
    <img src="/test_4.jpg" />5
    <img src="/test_5.jpg" />6
</ul>
 
<ul>
    어쩌구 저쩌구
</ul>
 
<script>
    script 어쩌구 
<script>
cs


위와 같이 되있는 텍스트를 파서를 돌리면

1
2
3
4
5
6
7
8
9
10
11
12
13
<ul class="u1">                                    
    <img src="/test_0.jpg" />1
    <img src="/test_1.jpg" />2
    <img src="/test_2.jpg" />3
    <img src="/test_3.jpg" />4
    <img src="/test_4.jpg" />5
    <img src="/test_5.jpg" />6
 
    script 어쩌구 저쩌구
 
    어쩌구 저쩌구
</ul>
 
cs


이런 식으로 파서가 되는 경우가 발생 합니다. 

스크립트 내용이 바디안으로 들어가서 tag들을 혼동을 주기도 합니다.


이럴땐 BeautifulSoup으로 나온 결과를 스트링으로 바꾸어서 다시 파서를 돌려야 합니다.

1
2
soup = BeautifulSoup(page, 'lxml')
BeautifulSoup(soup.text) or BeautifulSoup(soup.read())
cs


위와 같이 해주면 됩니다.

이건 해당 모듈의 문제로 어쩔 수 없는 부분이라 만약에 데이터가 파싱이 안되면 위 처럼 다시 파서를 돌려서 처리를 해야 할 것 같습니다.



파이썬에서는 scrapy라는 프레임 워크를 제공을 합니다.


scrapy를 통해 프로젝트를 생성을 하면



와 같이 디렉토리가 생성이 되는데


위에서 mung은 프로젝트 명입니다.


프로젝트로 들어가면 

items.py, middlewares.py, pipelines.py, settings.py, /spider가 생성이 됩니다


items.py는 수집 하고자 하는 데이터의 모델을 만듭니다.

middlewares.py는 데이터가 저장 되기 전에 정규화를 하는 과정이라고 보면 됩니다.

pipelines은 데이터를 저장하는 곳 입니다. 디비로 저장을 하거나 파일로 저장을 하거나 합니다.

setting.py는 크롤러의 설정 파일인데 각종 설정들을 변경을 해줍니다.

기본적으로 scrapy 프로젝트를 만들어서 크롤러를 실행하면 각종 로그가 찍히게 됩니다 이럴땐

LOG_LEVEL = 'WARNING'

를 추가를 하면 쓸데없는 로그가 찍히지 않게 됩니다.


다음으로는 실질적으로 데이터를 수집을 하는 부분인 /spider 디렉토리입니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import scrapy
from bs4 import BeautifulSoup
 
class DmozSpider(scrapy.Spider):
    name = "m"
    start_urls = [
        'url'
    ]
 
    def parse(self, response):
        title = response.xpath('//h3[@class="tit-prd"]/text()').extract()
        print(title)
        title = response.css('div h2').extract()
        print(title)
        for sel in response.xpath('//select'):
            title = sel.xpath('option/text()').extract()
        
        soup = BeautifulSoup(response.text, 'html5lib')
cs


$ scrapy crawl m


위처럼 scrapy crawl [name]을 주면 해당 크롤러를 동작시킬 수 있습니다. 그러면 start_urls의 링크들을 접속을 하여 해당응답 객체를 parse의 두번째 인자로 콜백을 합니다.


scrapy는 xpath방식을 이용하여 돔을 제어를 하지만 css selector방식을 이용하여 돔을 제어를 할 수 있습니다. 개인적으로는 후자가 더 편한 것 같습니다. 전자는 뭔가 정감이 가지 않더군요 ㅋㅋㅋㅋ


위의 내용들은 사소해 보일 수 있는 부분들인데 저것들이 갑자기 터지면 은근히 시간을 엄청 잡아먹는 부분들 입니다. 하나하나 해결하는데 몇날 몇일씩 걸렸던것 같네요 많게는 거의 몇달동안 해결이 안된 것들도 있었고... ㅋㅋ


그럼이만~

'서버 > 크롤러' 카테고리의 다른 글

image download  (0) 2017.05.10
Comments