본문 바로가기
IT & 개발공부/파이썬(Python)

scrapy를 이용한 웹 크롤링 실습

by 규딩코딩 2023. 8. 10.

 

- 파이썬의 다양한 크롤링 라이브러리를 배워보고 있다. 이번시간에는 beautifulsoup, selenium 다음으로 scrapy를 한 번 사용해보고자 한다.

 

0. 준비하기

- pip install scrapy로 라이브러리를 먼저 설치해주고, 프로젝트를 생성해보자(밑줄 친 부분은 임의 변경 가능)

scrapy start project scrapy_practice 명령어 실행

- 다음과 같이 여러 파일들이 추가된 구조를 확인할 수 있다.

1. 본격 크롤링

- 목표로 하는 크롤링 url 주소는 이것이다. : https://www.worldometers.info/world-population/population-by-country/

 

- 다음과 같이 명령어를 실행하자(위치 : spiders 폴더로 이동 후 명령어 실행)

- 명령어의 결과로 worldometer.py 파일이 생성된다. 

 

- 해당 파일에 코드가 이미 작성되어있는데, 아래와 같이 코드를 수정해주자.

import scrapy

class WorldometerSpider(scrapy.Spider):
    name = "worldometer"
    allowed_domains = ["www.worldometers.info/"]
    start_urls = ["http://www.worldometers.info/world-population/population-by-country"]

    def parse(self, response):
        title = response.xpath('//h1/text()').get()
        countries = response.xpath('//td/a/text()').getall()

        yield {
            'titles' : title, 
            'countries' : countries,
        }

 

- 이제 이 코드를 worldometer.py 가 있는 폴더에서 실행해보자. 명령어는 scrapy crawl worldometer 이며, 결과는 아래 이미지 처럼 출력될 것이다.

어디서 많이 본 것 같은 이 자료는 위의 웹페이지 화면에서 참고하면 되겠다.

 

2. Multiple links 가져오기

- 이번에는 다음 코드를 이용하여 해당 웹사이트 내의 다양한 링크를 가져와보도록 하자.

import scrapy

class WorldometerSpider(scrapy.Spider):
    name = "worldometer"
    allowed_domains = ["www.worldometers.info/"]
    start_urls = ["http://www.worldometers.info/world-population/population-by-country"]
################################# 상 동 #################################
    def parse(self, response):

        countries = response.xpath('//td/a')
        for country in countries:
            country_name = country.xpath(".//text()").get()
            link = country.xpath(".//@href").get()

            yield {
                'country_name' : country_name, 
                'link' : link
                            }

- 이번 코드는 국가 이름과 해당 국가 페이지의 링크를 추출하는 기능을 구현한 코드이다.

countries = response.xpath('//td/a'): 페이지에서 모든 <td> 요소 내부의 <a> 요소를 선택하여 countries 변수에 저장함으로써 각 국가의 정보가 포함된 요소를 가져올 수 있다.

 

country_name = country.xpath(".//text()").get(): 현재 국가 요소에서 텍스트를 추출하여 country_name 변수에 저장함.

link = country.xpath(".//@href").get(): 현재 국가 요소의 href 속성 값을 추출하여 link 변수에 저장함.

* //@href는 모든 요소의 href 속성을 선택한다.

yield: 추출한 국가 이름과 링크를 딕셔너리 형태로 정리하여 반환함.

 

- 이제 이 코드를 worldometer.py 가 있는 폴더에서 실행해보자. 명령어는 scrapy crawl worldometer 이며, 결과는 아래 이미지 처럼 출력될 것이다.

국가이름, 링크&nbsp; . . . 반복이다.

 

3. Multiple links 데이터를 추출하기

- 데이터 추출을 위해 먼저 XPath를 확인하자.

- 위 화면에서 Ctrl + F를 입력 후 다음과 같이 입력 후 검색한다.

(//table[@class="table table-striped table-bordered table-hover table-condensed table-list"])[1]

- 다음은 tr 태그에 접근하기 위해 다음과 같이 검색해보자.

(//table[@class="table table-striped table-bordered table-hover table-condensed table-list"])[1]/tbody/tr

 

- 노란색 표시가 되어있는 부분들을 클릭하다보면, 해당 하는 행이 선택되는 걸 확인할 수 있다.

 

- 이러한 정보를 조합한 결과 전체 코드는 다음과 같다. ★

import scrapy

class WorldometersSpider(scrapy.Spider):
    name = 'worldometer'
    allowed_domains = ['www.worldometers.info']
    start_urls = ['https://www.worldometers.info/world-population/population-by-country/']

    def parse(self, response):
        # a 요소 확인
        countries = response.xpath('//td/a')

        # 반복문
        for country in countries:
            country_name = country.xpath(".//text()").get()
            link = country.xpath(".//@href").get()

            # 절대경로
            # absolute_url = f'https://www.worldometers.info/{link}'  # 방법 1
            # yield scrapy.Request(url=absolute_url)  # sending a request with the absolute url

            # 상대경로
            yield response.follow(url=link, callback=self.parse_country, meta={'country':country_name})

    # Getting data inside the "link" website
    def parse_country(self, response):
 
        country = response.request.meta['country']
        rows = response.xpath("(//table[contains(@class,'table')])[1]/tbody/tr")  
        for row in rows:
            year = row.xpath(".//td[1]/text()").get()
            population = row.xpath(".//td[2]/strong/text()").get()

            # Return data extracted
            yield {
                'country':country,
                'year': year,
                'population':population,
            }

 

- 다음의 명령어 " scrapy crawl worldometer -o population.json " 를 입력하면, json 파일이 생기게 된다.

* 같은 명령어에서 가장 뒤를 .csv 로 하면 csv 파일로도 저장이 가능하다

 

- 추가로 만약에 데이터 프레임으로 불러오고 싶다면, 다음의 절차를 따르면 된다.

- .json 파일이 위치한 동일한 디렉토리 경로에 get_df.py(이름 임의로) 파일을 만들고 다음과 같이 코드를 작성해주면 된다.

* scrapy에서 물론 방법이 있겠지만, json파일로 저장한 뒤 불러오는 방식으로 DF를 만드는 것을 대부분 선호한다고 한다.

import pandas as pd

# json 파일 불러오기
def main():
    data = pd.read_json("population.json")
    data = pd.DataFrame(data)

    print(data.head())

if __name__ == "__main__":
    main()

 

- 결과 확인

 

 

 

 

 

 

★ 이 부분이 중요하면서, 꽤나 이해가 어려운 부분이었다. scrapy 사용 전 복습과 재실습이 필요해보인다.

https://curriculum.cosadama.com/scrapy/1-1/

반응형