- web crawling : 자동적으로 화면에 있는 data를 가져오는 것 (실시간 연동, 자동으로 업데이트 됨)
- web scrapping : 자동화 X / scrapping 하는 시점에서의 데이터만 갖고오기!
=> 두 가지 모두웹 사이트를 분석해 원하는 데이터를 추출하는 과정
이다.
web crawling에 사용되는 tool은 두가지 이다.
동적인 입력이 필요할 때 (가상의 브라우저를 띄워 사람 대신 이것저것 클릭 or 검색 해준다.)
Selenium
을 통해 동적인 입력이 들어간 뒤 모은 정보를 BeautifulSoup
에 전달BeautifulSoup
에서는 전달받은 정보를 데이터에 저장대상 웹페이지 = https://books.toscrape.com/
pip install beautifulsoup4
/ //pr1.py 생성
import requests
from bs4 import BeautifulSoup
response = requests.get("https://books.toscrape.com/")
bs = BeautifulSoup(response.text, 'html.parser')
#default > div > div > div > div > section > div:nth-child(2) > ol > li:nth-child(1) > article > div.image_container > a > img
위 코드를 보면 내가 선택한 영역의 tag
들을 가져왔다!!
+) 여기서 살펴보면
<img src="media/cache/2c/da/2cdad67c44b002e7ead0cc35693c0e8b.jpg" alt="A Light in the Attic" class="thumbnail">
이 코드가 실제 해당 영역을 가리키는 코드이다.
img 태그에 src
와 alt
속성이 들어있다.
위에 가져온 태그들 중, img 태그 안의 alt 속성에 대한 값을 출력시켜 보자!!
title_one = bs.selec_one("#default > div > div > div > div > section > div:nth-child(2) > ol > li:nth-child(1) > article > div.image_container > a > img")
print(title_one['alt'])
-> A Light in the Attic
코드를 살펴보면 같은 형식으로 표현되어 있는 책들의 경우 코드의 구성이 똑같다. (간혹 아닌것도 있으니 코드를 잘 구분할 줄 알아야 한다...)
각각의 책들은코드 구성이 같다가 li:nth-child
에서 숫자에 변화가 있다. 따라서 이 부분을 공통적인 부분으로 잡아준다면 이러한 구성의 태그에 해당하는 모든 요소가 title에 담길 것이다.
위 화면에서 개발자 도구 화면을 보면 모두 li
태그로 구분되고 있음을 알 수 있다!
title = bs.select("#default > div > div > div > div > section > div:nth-child(2) > ol > li > article > div.image_container > a > img")
for i in title:
print(i['alt'])
여기서 값들은 list
형태로 저장된다. 만약 print(i) 만을 한다면 <img alt="Set Me Free" class="thumbnail" src="media/cache/5b/88/5b88c52633f53cacf162c15f4f823153.jpg"/>
이련 형태로 출력된다. 내가 원하는 것은 그 속의 alt
에 담긴 책의 제목이기 때문에 print(i['alt'])
로 입력한다.
A Light in the Attic
Tipping the Velvet
Soumission
Sharp Objects
Sapiens: A Brief History of Humankind
The Requiem Red
The Dirty Little Secrets of Getting Your Dream Job
The Coming Woman: A Novel Based on the Life of the Infamous Feminist, Victoria Woodhull
The Boys in the Boat: Nine Americans and Their Epic Quest for Gold at the 1936 Berlin Olympics
The Black Maria
Starving Hearts (Triangular Trade Trilogy, #1)
Shakespeare's Sonnets
Set Me Free
Scott Pilgrim's Precious Little Life (Scott Pilgrim #1)
Rip it Up and Start Again
Our Band Could Be Your Life: Scenes from the American Indie Underground, 1981-1991
Olio
Mesaerion: The Best Science Fiction Stories 1800-1849
Libertarianism for Beginners
It's Only the Himalayas
css tag들을 보면 img 태그에 src
alt
속성이 담겨 각각 이미지 주소
와 이미지에 부합하는 책의 제목
이 적혀있다. 이것을 이용해 하나의 경로로부터 두가지 속성을 각각 출력시켜 보자!
import requests
from bs4 import BeautifulSoup
a = "https://books.toscrape.com"
response = requests.get(a)
bs = BeautifulSoup(response.text, 'html.parser')
book_1 = bs.select_one("#default > div > div > div > div > section > div:nth-child(2) > ol > li:nth-child(1) > article > div.image_container > a > img")
book_1_title = book_1['alt']
book_1_url = book_1['src']
print("book_1의 이미지 주소는 :", a+"/"+book_1_url)
print("book_1의 제목은 :", book_1_title)
일부러 이미지 주소 앞에 홈페이지 주소도 같이 출력되게 했다! 저 터미널상에서 command를 누르고 클릭하면 이미지 화면으로 이동한다 ^0^
bs 를 통해 얻어진 데이터를 csv 파일에 저장시킬 수 있다!! 먼저 설정해 줘야 할것이 있다.
import re
import csv
// csv 파일 열어두기
csv_name = "books.csv" //데이터들이 저장되면서 새로 생길 csv 파일의 이름
csv_open = open(csv_name, "w+", encoding = "utf-8")
csv_writer = csv.writer(csv_open)
csv_writer.writerow(('title','image_url'))
// bs 관련 코드 생략
// 각 타이틀 이름과 이미지 url을 모두 csv 파일에 저장
with open(csv_name, "w+", encoding = "utf-8") as file:
for i in range(len(titels)):
title = titles[i]['title']
img_url = a+'/'+image_urls['src']
writer = csv.writer(file)
writer.writerow([title, img_url])
여기서 변수 title과 image_url은 아래에서 선언할 것이다. 미리 쓴 것 뿐!
import re
import csv
import requests
from bs4 import BeautifulSoup
csv_name = "books.csv"
csv_open = open(csv_name, "w+", encoding = "utf-8")
csv_writer = csv.writer(csv_open)
csv_writer.writerow(('title','image_url'))
a = "https://books.toscrape.com"
response = requests.get(a)
bs = BeautifulSoup(response.text, 'html.parser')
same = bs.select("#default > div > div > div > div > section > div:nth-child(2) > ol > li:nth-child(1) > article > div.image_container > a > img")
with open(csv_name, "w+", encoding = "utf-8") as file:
for i in range(len(same)):
title = same[i]['title']
img_url = a+'/'+same[i]['src']
writer = csv.writer(file)
writer.writerow([title, img_url])
제일 위에 import re
가 뭔지 몰라서 지우고도 실행했는데 같은 결과(csv에 정보 저장)가 나왔다!! 없애도될꺼같은데....? 뭔지 알아보기!!!!
근데 왜 첫번째 책 제목이 잘려서 입력되는지 모르겠다... 왜....?
csv ?
comma-separated values : 몇 가지 필드를 쉼표(,)로 구분한 텍스트 데이터 및 텍스트 파일
selenium을 사용하기 위해선 다음의 모듈을 설치해야 한다.
import csv
import time //selenium에 직접적인 것은 아님!
from bs4 import BeautifulSoup
from selenium import webdriver
from webdriver_manager.chrome import ChromeDriverManager
csv_filename = "pr2.csv"
csv_open = open(csv_filename, "w+", encoding='utf-8')
csv_writer = csv.writer(csv_open)
//selenium을 통해 각 카테고리를 클릭할 수 있으므로 이 또한 정보이다. 카테고리도 함께 저장하기 위해 코드를 추가한다.
csv_sriter.sriterow(('category', 'title', 'image_url'))
driver = webdriver.Chrome(ChromeDriverManager().install())
a = "https://books.toscrape.com/"
driver.get(a)
full_html = driver.page_source
soup = BeautifulSoup(full_html, 'html.parser')
time.slepp(3) // selenium으로 새롭게 로딩되는 페이지 기다려 주는 시간
categories = soup.select('#default > div > div > div > aside > div.side_categories > ul > li > ul > li > a')
for i in range(1, len(categories)+1):
element = driver.find_element_by_css_selector(f'#default > div > div > div > aside > div.side_categories > ul > li > ul > li:nth-child({i}) > a')
category_name = element.text
time.sleep(2)
element.click() //selenium이 클릭!
full_html = driver.page_source
soup = BeautifulSoup(full_html, 'html.parser')
same = driver.find_elements_by_css_selector("#default > div > div > div > div > section > div:nth-child(2) > ol > li:nth-child(1) > article > div.image_container > a > img")
//각 타이틀 이름, 이미지 url 프린트 하기
for i, title in enumerate(same):
print('title: ', title['alt'])
print('original src: ', title['src'])
print('image_url: ', title['src'].split('/')[4:])
url = a + '/'+'/'.join(title['src'].split('/')[4:])
if i == 0:
csv_writer.writerrow((category_name,title['alt'], url))
else:
csv_writer.writerow(('',title['alt'], url))