web crawling-html/get/CSS SELECTOR + 셀레니움

엔지니어 큐브·2023년 8월 25일

웹 크롤링

목록 보기
4/4

1. HTML 구성 요소

  • Document : 한페이지를 나타내는 단위
  • Element : 하나의 레이아웃을 나타내는 단위 : 시작태그, 끝태그, 텍스트로 구성
  • Tag : 엘리먼트의 종류를 정의 : 시작태그(속성값(href)), 끝태그
  • Attribute(href) : 시작태그에서 태그의 특정 기능을 하는 값, 속성 값을 선택하는데 사용되는게 id와 class임
    • id : 웹 페이지에서 유일한 값 -> 1개만 선택할 때 사용
    • class : 동일한 여러개의 값 사용 가능 : element를 그룹핑 할때 사용 -> 여러개 선택할 때 사용
    • attr : id와 class를 제외한 나머지 속성들s
  • Text : 시작태그와 끝태그 사이에 있는 문자열
  • 엘리먼트는 서로 계층적 구조를 가질수 있습니다.

2. html 문법은 1번 파일 참고하셈

2. 셀레니움 사용법은 5번 파일 참고하셈..

3. CSS SELECTOR

  • 자세한 예시와 내용은 2번 파일 참고 하셈.

  • select element : css selector를 사용

  • tag name : div

  • id name : #wrap

  • class name : .wrap

  • attr name : [value="name"]

  • .n1, .n2 : n1, n2 클래스 엘리먼트 선택함

  • .ds:not(.ds2) : .ds에서 .ds2 제외해서 선택함

  • nth-child : .ds:nth-child(2) : 2번째 엘리먼트 중에 .ds를 갖는 엘리먼트 선택

  • .wrap p : 모든 하위 엘리먼트에서 검색해서 선택

  • .wrap > p : 한단계 하위 엘리먼트 검색해서 선택

4. 예제-네이버 연관 검색어 수집(keyword : 1개)

import pandas as pd
import requests
from bs4 import BeautifulSoup

query = '삼성전자'
url = f'https://search.naver.com/search.naver?sm=tab_hty.top&where=nexearch&query={query}'

response = requests.get(url)
response
response.text  -> **html**임을 확인할 수 있음.
  • 여기서 부터 json이랑 달라짐. json은 list, dict 형태라서 df로 변환하기가 편했다. 하지만, html은 bs와 객체, select를 사용해야 함.

  • response를 bs사용해서 1) 객체를 만들고 select 사용해서 2) json과 비슷한 형태를 만들어줌. select와 for문 사용해서 3) list를 만들고 4) df를 만들어주는 흐름이다.

# 1. str(html) -> bs object(객체)
dom = BeautifulSoup(response.text, 'html.parser')
type(dom)   <출력> bs4.BeautifulSoup

# 2. bs object > .select(css-selector), .select_one(css-selector) > str(text)
elements = dom.select('.lst_related_srch > .item')

# 3. str(text) -> df
[확인하고]
element = elements[0]
keyword = element.select_one('.tit').text   
<출력> '삼성전자주가'

 	- .select_one() : 1개만 선택하는 거임
    - ()안에는 클래스를 넣음
    
[실행함]
keywords = []
for element in elements:
    keyword = element.select_one('.tit').text
    keywords.append(keyword)

# 4. df 생성
from datetime import datetime
now = datetime.now().strftime('%Y-%m-%d %H:%M')

df = pd.DataFrame({'keyword' : keywords})
df['query'] = query
df['datetime'] = now
df  <출력>
	keyword			query		datetime
0	삼성전자주가		삼성전자	2023-08-25 12:20
1	삼성전자 배당금	삼성전자	2023-08-25 12:20
2	삼성전자서비스		삼성전자	2023-08-25 12:20
3	삼성전자주식		삼성전자	2023-08-25 12:20
4	오늘 삼성전자 주가	삼성전자	2023-08-25 12:20
5	삼성전자 배당금 지급일	삼성전자	2023-08-25 12:20
6	삼성전자몰			삼성전자	2023-08-25 12:20
7	삼성 전자레인지		삼성전자	2023-08-25 12:20
8	삼성전자 채용			삼성전자	2023-08-25 12:20
9	삼성전자 고객센터	삼성전자	2023-08-25 12:20

# 5. 함수 생성
def naver_relate_keywords(query):
    url = f'https://search.naver.com/search.naver?sm=tab_hty.top&where=nexearch&query={query}'
    response = requests.get(url)
    dom = BeautifulSoup(response.text, 'html.parser')
    elements = dom.select('.lst_related_srch > .item')
    keywords = [element.select_one('.tit').text for element in elements]
    now = datetime.now().strftime('%Y-%m-%d %H:%M')
    
    df = pd.DataFrame({'keyword' : keywords})
    df['query'] = query
    df['datetime'] = now
    
    return df

5. 예제-gmarket(베스트상품)(keyword:여러개)

import pandas as pd
import requests
from bs4 import BeautifulSoup

url = 'https://www.gmarket.co.kr/n/best'
response = requests.get(url)
response
response.text

# 1
dom = BeautifulSoup(response.text, 'html.parser')

[확인하고]
elements = dom.select('#gBestWrap > div.best-list > ul> li')
element = elements[0]
data = {
    'title' : element.select_one('.itemname').text,
    'link' : element.select_one('.itemname').get('href'),
    'image' : 'http:' + element.select_one('.image__lazy').get('src'),
    'o_price' : element.select_one('.o-price').text,
    's_price' : element.select_one('.s-price').text.split(' ')[0],
}
data    
<출력>
{'title': '네추럴라이즈 키즈 멀티비타민 C/D 60꾸미 3종 3병',
 'link': 'http://item.gmarket.co.kr/Item?goodscode=3113057185&ver=20230825',
 'image': 'http://gdimg.gmarket.co.kr/3113057185/still/300?ver=20230825',
 'o_price': '정가22,900원',
 's_price': '할인가21,760원'}
 
 
[실행 함]
items = []
for element in elements:
    items.append({
    'title' : element.select_one('.itemname').text,
    'link' : element.select_one('.itemname').get('href'),
    'image' : 'http:' + element.select_one('.image__lazy').get('src'),
    'o_price' : element.select_one('.o-price').text,
    's_price' : element.select_one('.s-price').text.split(' ')[0],
    })

#2 df 생성
df = pd.DataFrame(items)
df[['o_price', 's_price']].head(5)
<출력>
	o_price			s_price
0	정가22,900원	할인가21,7601	정가15,000원	할인가9,9802	정가25,800원	할인가12,9003				  할인가45,9004	정가325,000원	할인가144,900-> 1) 한글 삭제, 컴마 삭제, 2) 결측치 채움

1)
def change_number(data):
    return data.replace(',','')[2:-1]
    
df1 = df.copy()
df1['o_price'] = df1['o_price'].apply(change_number)
df1['s_price'] = df1['s_price'].apply(change_number)

2)
# 결측치를 s_price로 채울꺼임
#df1['o_price'][조건식을 통한 True 값] 이렇게 해서 조회도 가능 함

df1['o_price'][df2['o_price'] == ''] = df1['s_price']
df1['o_price'] = df1['o_price'].astype('int')
df1['s_price'] = df1['s_price'].astype('int')

#3이미지 다운로드

df3 = df1.copy()
df3 = df3[['title', 'image']]

import os                          #폴더 만들어 준거임
dname = 'imgs'
if not os.path.exists(dname):
    os.makedirs(dname)

link = df3.loc[0, 'image']
response = requests.get(link)
with open(f'{dname}/test.png', 'wb') as file:   #텍스트 저장은 'wt'
    file.write(response.content)
from PIL import Image as pil
pil.open(f'{dname}/test.png')

for idx, data in df3[:5].iterrows():        #사진 200개 다 저장됨
    print(idx, data['image'])
    response = requests.get(data['image'])
    with open(f'{dname}/{idx}.png', 'wb') as file: 
        file.write(response.content)
        
pil.open(f'{dname}/3.png')
profile
큐브가 필요하다...!!!

0개의 댓글