티스토리 뷰
잔재미코딩님의 강의를 보며 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문이 돌아가는데 왜 서브 메뉴 파서가 작동이 안하는길까...
구글에 스크래피 중복 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 튜토리얼 하고
하나하나 도장꺠기하는 거 같아서 재미가있다잉
힘내자!
'코드' 카테고리의 다른 글
알고리즘따위 1도 모르는 코딩초보자, TextRank에 TF-IDF적용 분투기 (0) | 2019.11.04 |
---|---|
[SCRAPY/PYTHON] scrapy 로 wiki 크롤링하다가 마주친 오류 (0) | 2019.10.30 |
[python, MySQL] from 파이썬 크롤러 to MySQL via pymysql (0) | 2019.10.17 |
[python] gmarket 크롤러 중에 마주친 오류 (0) | 2019.10.16 |
BeautifulSoup 모듈 find와 select의 차이점 - 복잡한 웹을 간단하게 (6) | 2019.10.16 |
- Total
- Today
- Yesterday
- 일기
- 유튜버
- 이슈
- BeautifulSoup
- 유럽
- Crawling
- 오류
- error
- flask
- DATABASE
- HTML
- 저널
- coding
- 블로그
- NLP
- css
- Selenium
- 코로나
- 마드리드
- 파이썬
- nltk
- 항공
- scrapy
- 스페인
- 유튜브
- 글쓰기
- 런업
- 리뷰
- python
- 분석
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |