티스토리 뷰

잔재미코딩님의 강의를 보며 scrapy 튜토리얼을 배워나가고 있다.

기본적인 흐름은 다음과 같다.

1. scrapy startproject [projectname] 으로 새 프로젝트 폴더를 생성한다. 

2. scrapy genspider [filename] [domain] 으로 사이트 주소를 start url로 가지는 파일을 생성한다.
2-1. 크롤링하려는 사이트를 scrapy shell 을 통해 크롤러 코드 제작 전에 미리 실험해 볼 수 있다.

# -*- coding: utf-8 -*-
import scrapy

class HelloSpider(scrapy.Spider):
    name = 'hello'
    allowed_domains = ['www.naver.com']
    start_urls = ['http://www.naver.com/']

    def parse(self, response):
        pass

3. 위 프로젝트 파일에 크롤링 코드를 제작한다.

3-1. 기본 생성되는 클래스의 start_url 클래스 속성을 이용하거나 strat_request 함수를 정의하여 시작점을 정의한다.

class TestSpider(scrapy.Spider):
	name = 'Test' #인덴트 이상해
    
    def start_request(self):
    	yield scrapy.Request(url='[yoururlhere]', callback=self.[parsernamehere])

yield로 scrapy의 Request모듈 객체를 생성한다. url을 입력하고 callback에는 어떤 파서를 이용할지 설정한다.

3-2. 파서 함수를 정의한다.

from crawltest.items import CrawltestItem
#item.py 파일에서 클래스 모듈을 불러와야 필드를 선언하여 데이터를 입력할 수 있다.

def parse_item(self, response):
	titles = response.css('-').getall() #인덴트가 또 이러네
    contents = response.css('-').getall()
    
    for index, title in enumerate(titles):
    	dataset = CrawltestItem()
       	dataset['title'] = title
        dataset['content'] = contents[index]
        
        yield dataset

start_request 함수에서 yield로 생성된 request 객체를 매개변수로 받는다.
객체에서 css셀렉터로 원하는 자료를 크롤링한다.
(get() 과 getall() 은 BS의 select_one() 와 select() 의 관계와 같다)

for문에서 titles 리스트에 enumerate로 인덱스를 붙여 인덱스 넘버로 해당되는 content를 저장한다.
import한 클래스 모듈을 객체로 만든다.
미리 설정된 객체의 필드에 데이터를 입력한다.

*상위 프로젝트 폴더의 items.py 파일은 크롤링할 내용을 정의할 수 있다.

import scrapy

class CrawltestItem(scrapy.Item):
    title = scrapy.Field()
    content = scrapy.Field()

4. cmd창에서 scrapy crawl [spidername] -o [filename].csv(확장자) -t csv(파일유형) 를 입력하세요 데이터 추출

__

이제 오류이야기를 해보자... 
정리하고 요약하는 건 재미가읍써!! 

내 스파이더의 구성은 :
1. 메인 페이지 접속
2. 메인 페이지 리퀘스트 객체를 메뉴파서에 전달
3. 메뉴 파서에서 메뉴 링크 리스트를 for문으로 아이템파서에 전달 : 원하는 자료 크롤링 (depth1)
4. 메뉴파서에서 for문을 한 번 더 반복하여 메뉴 링크 리스트를 for문으로 서브 메뉴 파서에 전달
5. 서브 메뉴 파서에서 서브 메뉴 링크 리스트를 for문으로 아이템 파서에 전달 : 원하는 자료 크롤링 (depth2)

하아아아아지만 역시는 역시 오류가 난다.

3번과 4번에서 메뉴 파서에서 for문을 두 번 사용하여 각자 아이템파서와 서브메뉴 파서에 리퀘스트 객체를 전달하는데 두 번째 크롤링이 작동이 안됐다.

    def parse_mainpage(self, response):
        category_links = response.css('-').getall()
        category_names = response.css('-').getall()

        #1st category crawling
        for index, category_link in enumerate(category_links):
            yield scrapy.Request(url=''+category_link, callback=self.parse_items,
            meta={'maincategory_name':category_names[index]})

        #2st category crawling
        for index, category_link in enumerate(category_links):
            print("두번째 되고 잇나?") 
            yield scrapy.Request(url=''+category_link, callback=self.parse_subcategory, 
            meta={'maincategory_name':category_names[index]})
           
    def parse_subcategory(self, response):
        print('parse subcategory', response.meta['maincategory_name'])

그래서 두 번째 for문이 안되는건지 서브 메뉴 파서에서 리퀘스트 객체가 전달이 안되는건지 알아보기 위해 각각 프린트문을 넣어본다.

for문을 잘만 돌아간다..

for문이 돌아가는데 왜 서브 메뉴 파서가 작동이 안하는길까...
구글에 스크래피 중복 url 을 영어로 쳐보니까 scrapy duplicate urls라고 바로 자동완성이 뜬다.
다음은 scrapy docs에서 발견한 자료를 캡처해왔다.

사용 설명서를 잘 읽읍시다!

start_urls를 시작점으로 쓰면 리퀘스트 객체 생성을 중복해도 괜찮다는 dont_filter 가 기본적으로 true로 들어가는데 나는 메뉴 파서에서 리퀘스트 객체를 생성하니까 dont filter가 false로 되어있어 중복되는 리퀘스트 객체는 생성이 안되었다는 말씀. 그래서

        #2st category crawling
        for index, category_link in enumerate(category_links):
            print("두번째 되고 잇나?") 
            yield scrapy.Request(url=''+category_link, callback=self.parse_subcategory, 
            meta={'maincategory_name':category_names[index]}, dont_filter=True)

돈필터를 트루로 설정해주니 성공!!

__

월요일 좋아~
차근차근히 해나가는거 좋아~
유투브로 선형대수학이랑 nlp 보고 인프런으로 scrapy/atom/web 배우고 kaggle로 nltk 튜토리얼 하고 
하나하나 도장꺠기하는 거 같아서 재미가있다잉
힘내자!

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
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
글 보관함