[데이터과학] 데이터 수집하는 방법 (예제: 오라일리의 데이터 관련 책) - 페이지 스크랩, 정책

2021. 4. 28. 01:45 Python/Python 프로그래밍

오라일리 출판사 페이지 웹페이지를 분석해서 데이텀의 잠재적 투자자가 데이터 분석은 의미없는 유행에 불과하다는 생각이 틀리다는 것을 증명해보도록 하자.

 

http://shop.oreilly.com/category/browse-subjects/data.do?sortby=publicationDate%page=1

의 주소를 확인해보면 페이지당 30권씩 책이 표시되고 있는것을 확인 할 수 있다.

 

악의적으로 사이트에 접속하는 것이 아니거나, 웹 스크래퍼가 차단당하는 것을 원치 않는다면 가장 먼저 사이트의 접근 정책을 확인해야 한다.

 

http://oreilly.com/terms/

 

크롤러(스크래퍼)가 어떻게 작동해야 하는지 규제하고 있는 robots.txt를 확인해보면 된다. 

 

Crawl-delay: 30

Request-rate: 1/30

 

첫 번째는 매번 요청을 보내는 사이에 30초를 기다려야 한다는 것을 의미하고, 두번째는 30초마다 하나의 페이지만 요청하라는 것을 의미한다.

 

페이지의 소스를 보기 위해 오른쪽 마우스를 클릭 후 ‘페이지 소스보기’를 클릭한다.

소스를 보면 해당 웹페이지의 HTML 코드를 확인 할 수 있다. 

 

아래 코드를 통해서 스크랩 및 분석을 할 수 있다. 

 

from bs4 import BeautifulSoup
import requests
from time import sleep
base_url = "http://shop.oreilly.com/category/browse-subjects/data.do?sortby=publicationDate%page="

books = []

NUM_PAGES = 31

for page_num in range(1, NUM_PAGES + 1):
    url = base_url + str(page_num)
    soup = BeautifulSoup(requests.get(url).text, 'html5lib')

    tds = soup('td', 'thumbtext')
    print len(tds) # 30

    for td in soup('td', 'thumbtext'):
           if not is_video(td):
                books.append(book_info(td))
    sleep(30) # robots.txt
    
def is_video(td):
    pricelabels = td('span', 'pricelabel')
    return (len(pricelabels) == 1 and
            pricelabels[0].text.strip().startswith("Video"))

print len([td for td in tds if not is_video(td)])
def book_info(td):
    title = td.find('div', 'thumbheader').a.text
    author_name = td.find('div', 'AuthorName').text
    authors = [x.strip() for x in re.sub("^By", "", author_name).split(",")]
    isbn_link = td.find('div', 'thumbheader')a.get('href')
    isbn = re.match("/product/(.*)\.do", isbn_link).group(1)
    date = td.find('span', 'directorydate').text.strip()
    
    return {
        'title': title,
        'authors': authors,
        'isbn': isbn,
        'date': date
    }

def get_year(book):
    return int(book['date'].split()[1])

year_counts = Counter(get_year(book) for book in books
                      if get_year(book) <= 2014)

import matplotlib.pyplot as plt
years = sorted(year_counts)
book_counts = [year_counts[year] for year in years]
plt.plot(years, book_counts)
plt.ylabel('# of date books')
plt.title('data is big!')
plt.show()

[참고] 밑바닥부터 시작하는 데이터과학

 

출처 : ourcstory.tistory.com/218?category=630693