일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 | 31 |
- 라즈비안
- MongoDB
- 백준
- 13237
- raspberrypi
- nav-tab
- 라즈베리파이3
- 2579
- CSS
- 16.04
- 파이썬
- 알고리즘
- dp
- HTML
- Algorythm
- algotythm
- bootstrap
- Crawling
- 트리
- 라즈베리파이3b+
- 크롤링
- dynaminprogramming
- NAV
- springboot3.x
- node.js
- 라즈베리파이
- Python
- ubuntu
- baekjun
- 2909
- Today
- Total
노트
[Python] Selenium으로 중고나라 크롤링 후 MySQL에 저장 본문
안녕하세요!
이번엔 중고나라를 크롤링했습니다.
예전에 과제로 했던거라 기억은 잘 안나지만 최대한 써볼게요!
제가 크롤링한 부분은 중고나라의 미개봉 새상품 목록입니다.
크롤링할 데이터는 아래 내용입니다.
.
Selenium을 사용하기 위해서는 chrome web-driver가 필요한데
제 이전 게시물에서 설명했으니까 참고해 주세요.
참고로 저는 주피터 노트북으로 작업했습니다.
.
.
.
ln[1]:
#중고나라에서 크롤링으로 데이터 뽑기
from selenium import webdriver
import time
driver = webdriver.Chrome('C:/Users/samsung/Downloads/chromedriver')
driver.get('https://cafe.naver.com/joonggonara?iframe_url=/ArticleList.nhn%3Fsearch.clubid=10050146%26search.menuid=1900%26search.boardtype=L')
bb2 = []
dataset = []
time.sleep(2)
driver.switch_to.frame("cafe_main")
for l in range(1,71):
tag = driver.find_elements_by_xpath('//div[@class="article-board m-tcol-c"]//table/tbody/tr')
bb2 = tag
time.sleep(2)
for i in range(len(bb2)):
dataset.append(bb2[i].text)
if l % 10 == 0:
c10 = driver.find_element_by_link_text('다음')
c10.click()
else:
a = str(l+1)
c = driver.find_element_by_link_text(a)
c.click()
time.sleep(2)
driver.quit()
driver로 웹드라이버를 정의해주고, 크롤링하고싶은 웹페이지의 url을 넣어줍니다.
그리고 제가 크롤링하고 싶은 부분의 html 코드를 보면
이렇게 div태그가 iframe 안에 있는 것을 볼 수 있습니다.
코드에 driver.switch_to.frame("cafe_main") 을 넣어주면 iframe 안의 내용을 크롤링 할 수 있습니다.
그리고 for문에서 범위를 1~71이라고 한 이유는
한페이지당 목록이 15개정도 있어서 70페이지쯤 크롤링하면 1000개정도 되기 때문입니다.
.
tag = driver.find_elements_by_xpath('//div[@class="article-board m-tcol-c"]//table/tbody/tr')
html 태그로 찾는 것을 find_elements_by_xpath라고 하는데
iframe안의 '//' : 많은 태그들을 지나서
'div[@class="article-board m-tcol-c"]' : div안의 class이름이 article-board m-tcol-c 인 곳 아래의
'//' : 많은 태그들을 지나서
'table/tbody/tr' : table안의 tbody안의 tr 태그 안에
크롤링하려고 하는 모든 데이터들이 있습니다.
F12 키를 누르면 html소스를 볼 수 있으니까 직접 확인해보세요.
.
.
그리고 이렇게 태그 안의 검은색 글씨들을 text라고 하는데
.
dataset.append(bb2[i].text)
그래서 이 코드는 태그 안의 text들을 가져온다는 뜻입니다.
.
c10 = driver.find_element_by_link_text('다음')
이 부분은 중고나라에서 다음페이지로 표시하는 부분이 10페이지까지 표시되어서
10번 페이지를 넘기면 selenium으로 다음 버튼을 누르도록 했고
c = driver.find_element_by_link_text(a)
이 부분은 페이지번호 1, 2, 3, .. 을 각각 selenium으로 눌러주는 코드입니다.
find_element_by_link_text 라는 부분은
중고나라의 html코드를 확인해보시면 무슨 뜻인지 알 수 있을 것입니다.
.
.
중간중간에 sleep을 줘서 사이트가 충분히 로딩되도록 해주세요.
저같은 경우에는 크롤링하다가 자꾸 max try error였었나
암튼 저런게 떠서 sleep을 줬던것 같네요.
.
.
.
이렇게 해서 크롤링한 정보를 print해보면
이런 식으로 나오게 되는데
별로 보기에 예쁘지가 않죠?
그리고 DB에 저장하려면 규격을 맞춰야하므로 전처리를 해줍니다.
.
da = dataset
#중복된 이름 attribute 제거
d = len(da)-1
while d >= 0:
if d % 2 == 1:
del da[d]
d-=1
print(da[:27])
먼저 위에서 출력한 부분의 짝수번째 줄에 중복된 이름 데이터를 지워줍니다.
맨 밑의 코드에서 굳이 27을 출력한 이유는 제가 예전에 크롤링했을 때
1페이지에는 공지사항까지 같이 떠서 공지개수+게시물개수가 아마 27개라서 그랬던것 같습니다.
아무튼 이렇게 하면
이렇게 중복된 데이터가 사라집니다.
.
이제 공지사항을 삭제해줍니다.
위랑 비슷하게 코드를 짜면
dda = da
#공지사항 삭제
d = len(dda)-1
while d >= 0:
if '공지' in dda[d]:
del dda[d]
d -= 1
print(dda[:15])
지금 보니까 저 '필독'이란 부분도 지웠어야했는데 안지웠네요.
.
.
#new와 사진이 없는 경우, 둘 다 있는 경우, 둘 중 하나만 있는 경우
#\n으로 구분된 attribute들 나눠주고 마지막 값은
#'날짜(또는 시간) 조회수' 로 되어있으므로 공백으로 나눠준 후 append
data = []
for r in range(len(dda)):
a = dda[r].split('\n')
if len(a) == 4:
b = a[3].split(' ')
del a[3]
for i in b:
a.append(i)
data.append(a)
elif len(a) == 6:
b = a[5].split(' ')
del a[5]
for i in b:
a.append(i)
data.append(a)
else:
b = a[4].split(' ')
del a[4]
for i in b:
a.append(i)
data.append(a)
data
이부분은 그냥 mysql에 넣을 수 있도록 틀을 잡아주는 부분입니다.
#db에 저장하기위해 같은 길이의 리스트로 만들기
#사진이 없는 곳에 빈 공간 만들기
datas = data
dataas = []
for r in range(len(datas)):
tmp = []
tm = datas[r]
for t in range(len(tm)):
if t == 2 and tm[t] != '사진':
tmp.append('')
tmp.append(tm[t])
dataas.append(tmp)
dataas
#new가 없는 곳에 빈 공간 만들기
datas2 = dataas
real_dataset = []
for r in range(len(datas2)):
tmp = []
tm = datas2[r]
for t in range(len(tm)):
if t == 3 and tm[t] != 'new':
tmp.append('')
tmp.append(tm[t])
real_dataset.append(tmp)
real_dataset
이것도 틀잡는거
.
결과가 대충 이런식으로 나오는데 이러면 mysql에 한번에 집어넣기 편합니다.
.
그리고 데이터 중에 제목 데이터 뒤에 대부분 댓글수가 같이 붙어서 나오는데
몇개는 따로 떨어져서 나오더라구요. 이런걸 정리해줍니다.
저는 이런게 몇개 없어서 그냥 인덱스를 찾아서 그것만 지우는 식으로 했습니다.
#댓글 데이터가 제목이랑 붙어 나오는게있고 이렇게 나오는게 있어서
#그냥 이렇게 나오는걸 제거(2개밖에 없다)
for i in range(len(real_dataset)):
if len(real_dataset[i])>7:
print(i)
del real_dataset[i]
.
.
아 MySQL에는 작은따옴표(')는 안들어가니까 주의해주세요.
#mysql에는 작은따옴표를 넣을 수 없으므로 '를 찾아서 없애준다
for r in real_dataset:
if "'" in r[1]:
print(real_dataset.index(r))
이것도 하나밖에 없어서 그냥 하드코딩으로 지워줬었네요.
#216 하나밖에 없어서 그냥 없애줌
real_dataset[216][1] = real_dataset[216][1].replace("'",'')
real_dataset[216][1]
.
.
마지막으로 Mysql에 저장하는 부분입니다.
#DB에 저장
import pymysql
connect = pymysql.connect(host='localhost', user='유저명', password='비밀번호', db='디비이름', charset='utf8mb4')
cursor = connect.cursor()
for r in real_dataset:
boardnum = int(r[0])
title = str(r[1])
photo = str(r[2])
newornot = str(r[3])
uname = str(r[4])
utime = str(r[5])
readnum = int(r[6])
sql = """insert into contents
(boardnum, title, photo, newornot, uname, utime, readnum)
values (%d, '%s', '%s', '%s', '%s', '%s', '%d')
""" % (boardnum, title, photo, newornot, uname, utime, readnum)
cursor.execute(sql)
connect.commit()
connect.close()
mysql에 디비를 만든 후 이렇게 넣어주면 끝
스키마는
이렇게 했습니다.
.
.
<결과>
.
.
.
.
.
'코딩 > Python' 카테고리의 다른 글
파이썬 random() 사용하기 (0) | 2020.02.15 |
---|---|
주피터 노트북 꿀팁 (0) | 2020.02.14 |
파이썬을 이용한 유튜브 채널 크롤링, csv파일로 만들기 (12) | 2019.05.21 |