[빅 리더 AI] 크롤러 2일차

KrTeaparty·2022년 7월 6일
0

빅 리더 AI

목록 보기
3/7

항목별 내용 추출 후 다양한 형식의 파일로 저장

아래는 riss에서 키워드로 검색하여 옵션에 맞춰서 크롤링하고, 긁어온 데이터를 csv, xls로 저장하는 코드이다.

# riss.kr 에서 특정 키워드로 논문 / 학술 자료 검색하기

#Step 1. 필요한 모듈을 로딩합니다
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.chrome.service import Service
import time          

#Step 2. 사용자에게 검색 관련 정보들을 입력 받습니다.
print("=" *100)
print(" 이 크롤러는 RISS 사이트의 논문 및 학술자료 수집용 웹크롤러입니다.")
print("=" *100)
query_txt = input('1.수집할 자료의 키워드는 무엇입니까? : ')

#Step 3. 수집된 데이터를 저장할 파일 이름 입력받기 
ft_name = './result/riss_chap3.txt'
fc_name = './result/riss_chap3.csv'
fx_name = './result/riss_chap3.xls'

#Step 4. 크롬 드라이버 설정 및 웹 페이지 열기
s = Service("../chrome_driver/chromedriver.exe")
driver = webdriver.Chrome(service=s)

url = 'https://www.riss.kr/'
driver.get(url)
time.sleep(5)
driver.maximize_window()

#Step 5. 자동으로 검색어 입력 후 조회하기
element = driver.find_element(By.ID,'query')
driver.find_element(By.ID,'query').click( )
element.send_keys(query_txt)
element.send_keys("\n")
time.sleep(2)

#Step 6.학위 논문 선택하기
menu = int(input('''위 키워드로 아래의 장르 중 어떤 장르의 정보를 수집할까요?

1.학위논문\t2.국내학술논문\t3.해외학술논문\t4.학술지
5.단행본\t6.공개강의\t7.연구보고서

위 장르 중 수집할 장르의 번호를 입력하세요: '''))

menu_dict = {1:'학위논문', 2:'국내학술논문', 3:'해외학술논문', 4:'학술지', 5:'단행본', 6:'공개강의', 7:'연구보고서'}
driver.find_element(By.LINK_TEXT, menu_dict[menu]).click()
time.sleep(2)

#Step 7.Beautiful Soup 로 본문 내용만 추출하기
from bs4 import BeautifulSoup
html_1 = driver.page_source
soup_1 = BeautifulSoup(html_1, 'html.parser')

if menu ==1 :
    total_1 = soup_1.find('div','searchBox pd')
elif menu ==2 :
    total_1 = soup_1.find('div','searchBox')
elif menu ==3 :
    total_1 = soup_1.find('div','searchBox')
elif menu ==4 :
    total_1 = soup_1.find('div','searchBox pd')
elif menu ==5 :
    total_1 = soup_1.find('div','searchBox pd')
elif menu ==6 :
    total_1 = soup_1.find('div','searchBox pd')
elif menu ==7 :
    total_1 = soup_1.find('div','searchBox pd')

total_2 = total_1.select('dl > dd > span')
total_3 = total_2[0].find('span','num').get_text()
total = total_3.replace(",","")

time.sleep(1)

#장르 이름 지정하기
if menu == '1' :
    j_name='학위논문'
elif menu =='2':
    j_name='국내학술논문'
elif menu =='3':
    j_name='해외학술논문'
elif menu =='4':
    j_name='학술지'
elif menu =='5':
    j_name='단행본'
elif menu =='6':
    j_name='공개강의'
elif menu =='7':
    j_name='연구보고서'

#Step 8. 총 검색 건수를 보여주고 수집할 건수 입력받기
import math
print('검색하신 키워드 %s (으)로 총 %s 건이 검색되었습니다' %(query_txt,total))
collect_cnt = int(input('이 중에서 몇 건을 수집하시겠습니까?: '))
collect_page_cnt = math.ceil(collect_cnt / 10)
print('%s 건의 데이터를 수집하기 위해 %s 페이지의 게시물을 조회합니다.' %(collect_cnt,collect_page_cnt))
print('=' *80)

#Step 9. 각 항목별로 데이터를 추출하여 리스트에 저장하기
no2 = [ ]        #번호 저장
title2 = [ ]     #논문제목 저장
writer2 = [ ]    #논문저자 저장
org2 = [ ]       #소속기관 저장
year2 = [ ]      #발표년도
paper2 = [ ]       #논문집/자료집
pa_url2 = [ ]    #논문 URL정보
paper_cnt = range(1,11)
no = 1

for a in range(1, collect_page_cnt + 1) :
    
    html_2 = driver.page_source
    soup_2 = BeautifulSoup(html_2, 'html.parser')

    content_2 = soup_2.find('div','srchResultListW').find_all('li')
    cnt = 0
    
    for b in content_2 :    
        #1. 논문제목 있을 경우만
        try :
            title = b.find('div','cont').find('p','title').get_text()
        except :
            continue
        else :
            f = open(ft_name, 'a' , encoding="UTF-8")
            print('1.번호:',no)
            no2.append(no)
            f.write('\n'+'1.번호:' + str(no))

            print('2.논문제목:',title)
            title2.append(title)
            f.write('\n' + '2.논문제목:' + title)
            
            try:
                writer = b.find('span','writer').get_text()
            except:
                writer = "No Writer"
            print('3.저자:',writer)
            writer2.append(writer)
            f.write('\n' + '3.저자:' + writer)

            try:
                org = b.find('span','assigned').get_text()
            except:
                org = "No Org"
            print('4.소속기관:' , org)
            org2.append(org)
            f.write('\n' + '4.소속기관:' + org + '\n')
            
            etc = b.select('p > span')
            try:
                year = etc[2].get_text()
            except:
                year = "No Year"
            print('5.발표년도:' , year)
            year2.append(year)
            f.write('\n' + '5.발표년도:' + year + '\n')
            
            try:
                paper = etc[3].get_text()
            except:
                paper = "논문집 없음"
            print('6.논문집/자료집 or 학위:' , paper)
            paper2.append(paper)
            f.write('\n' + '6.논문집/자료집 or 학위:' + paper + '\n')
            
            pa_url = b.find('div', 'cont').find('p', 'title').find('a')['href']
            pa_url = 'http://www.riss.kr'+pa_url
            print('7.논문 URL 주소:' , pa_url)
            pa_url2.append(pa_url)
            f.write('\n' + '7.논문 URL 주소:' + pa_url + '\n')
            
            f.close( )
            
            no += 1
            print("\n")
            
            if no > collect_cnt :
                break

            time.sleep(1)        # 페이지 변경 전 1초 대기 

    a += 1 
    b = str(a)

    try :
        driver.find_element(By.LINK_TEXT ,'%s' %b).click() 
    except :
        driver.find_element(By.LINK_TEXT, '다음 페이지로').click()
        
print("요청하신 작업이 모두 완료되었습니다")

# Step 10. 수집된 데이터를 xls와 csv 형태로 저장하기
import pandas as pd 

df = pd.DataFrame()
df['번호']=no2
df['제목']=pd.Series(title2)
df['저자']=pd.Series(writer2)
df['소속(발행)기관']=pd.Series(org2)
df['발표년도']=pd.Series(year2)
df['논문집/자료집 or 학위']=pd.Series(paper2)
df['논문URL']=pd.Series(pa_url2)
# xls 형태로 저장하기
df.to_excel(fx_name,index=False, encoding="utf-8" , engine='openpyxl')

# csv 형태로 저장하기
df.to_csv(fc_name,index=False, encoding="utf-8-sig")

print('요청하신 데이터 수집 작업이 정상적으로 완료되었습니다')

수집하는 것은 제목, 저자, 소속기관, 발표년도, 논문집/자료집, 논문URL이다.

페이지를 자동으로 넘기기 위한 부분부터 보겠다.

#Step 8. 총 검색 건수를 보여주고 수집할 건수 입력받기
import math
print('검색하신 키워드 %s (으)로 총 %s 건이 검색되었습니다' %(query_txt,total))
collect_cnt = int(input('이 중에서 몇 건을 수집하시겠습니까?: '))
collect_page_cnt = math.ceil(collect_cnt / 10)
print('%s 건의 데이터를 수집하기 위해 %s 페이지의 게시물을 조회합니다.' %(collect_cnt,collect_page_cnt))
print('=' *80)

한 페이지에 10건씩 나오기 때문에 ceil()을 이용해 총 페이지 수를 구한다.

각 항목별로 데이터를 추출하여 리스트에 저장하는 이유는 csv, xls 형태로 저장하기 위해서는 표 형태로 되어야 하기 때문에 이후에 dataframe으로 묶기 위함이다.

크롤링을 할 때는 try/except/else/finally를 잘 쓰는 것이 필요하다.

이중 반복문으로 페이지용으로 하나, 게시물 반복용으로 하나를 사용한다.

pa_url = b.find('div', 'cont').find('p', 'title').find('a')['href']
pa_url = 'http://www.riss.kr'+pa_url
print('7.논문 URL 주소:' , pa_url)
pa_url2.append(pa_url)
f.write('\n' + '7.논문 URL 주소:' + pa_url + '\n')

a태그까지 가서 ['href']를 사용하면 a 태그에 있는 url을 가져올 수 있다.

try :
    driver.find_element(By.LINK_TEXT ,'%s' %b).click() 
except :
    driver.find_element(By.LINK_TEXT, '다음 페이지로').click()

이 try/except문은 페이지를 넘기는 용도이다. 웹페이지 중에는 페이지를 이동함에 따라 숫자가 따라서 이동하는 경우와 다음 버튼(>)을 눌러줘야 하는 경우가 있다.
그 둘을 모두 해결해주는 코드이다.

# Step 10. 수집된 데이터를 xls와 csv 형태로 저장하기
import pandas as pd 

df = pd.DataFrame()
df['번호']=no2
df['제목']=pd.Series(title2)
df['저자']=pd.Series(writer2)
df['소속(발행)기관']=pd.Series(org2)
df['발표년도']=pd.Series(year2)
df['논문집/자료집 or 학위']=pd.Series(paper2)
df['논문URL']=pd.Series(pa_url2)

Series를 사용하는 이유는 혹시라도 결측값이 있다면 데이터프레임에 넣을 떄 문제가 발생하기 때문이다.

# xls 형태로 저장하기
df.to_excel(fx_name,index=False, encoding="utf-8" , engine='openpyxl')

# csv 형태로 저장하기
df.to_csv(fc_name,index=False, encoding="utf-8-sig")

print('요청하신 데이터 수집 작업이 정상적으로 완료되었습니다')

dataframe을 저장할 때는 to_csv, to_excel을 이용한다.

riss.kr에서 특정 키워드로 논문/학술 자료 검색

# Chap 15.riss.kr 에서 특정 키워드로 논문 / 학술 자료 검색하기
#Step 1. 필요한 모듈을 로딩합니다
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.chrome.service import Service
import time
#Step 2. 사용자에게 검색 관련 정보들을 입력 받습니다.
print("=" *100)
print(" 이 크롤러는 연습문제용 웹크롤러입니다.")
print("=" *100)

#Step 3. 수집된 데이터를 저장할 파일 이름 입력 받기
f_dir = './result/'

#Step 4. 크롬 드라이버 설정 및 웹 페이지 열기
s = Service("../chrome_driver/chromedriver.exe")
driver = webdriver.Chrome(service=s)
url = 'http://eungdapso.seoul.go.kr/'
driver.get(url)
driver.maximize_window()
time.sleep(2)

#Step 5. 자동으로 검색어 입력 후 조회하기
element = driver.find_element(By.CLASS_NAME,'izc-btn').click()
time.sleep(1)

from bs4 import BeautifulSoup
html_1 = driver.page_source
soup_1 = BeautifulSoup(html_1, 'html.parser')

import math
cnt = 58
page_cnt = math.ceil(cnt / 10)

no2 = []
title2 = []
date2 = []
contents2 = []
f = open(f_dir+'chap4.txt', 'w', encoding='utf8')
no = 1
cnt_list = range(2, 12)


for a in range(1, page_cnt+1):
    print("\n")
    print("%s 페이지 내용 수집 시작합니다 =======================" %a)
    html = driver.page_source
    soup = BeautifulSoup(html, 'html.parser')
    content_list = soup.find('div','pclist_table mt20').find_all('tr','pclist_list2')
    for i in content_list:
        driver.find_element(By.XPATH, '//*[@id="content_cont"]/div[2]/div/form/div[4]/table/tbody/tr[{}]/td[2]/a'.format(cnt_list[(no-1)%10])).click()
        time.sleep(2)
        html2 = driver.page_source
        soup2 = BeautifulSoup(html, 'html.parser')
        no2.append(no)
        
        try:
            title = driver.find_element(By.XPATH, '//*[@id="content_cont"]/div[2]/div/table[1]/tbody/tr[1]/td').text
        except:
            title = "제목 없음"
        title2.append(title)
        print('1.제목: ', title)
        f.write('\n'+'1.제목: '+title)
        
        try:
            date = driver.find_element(By.XPATH, '//*[@id="content_cont"]/div[2]/div/table[1]/tbody/tr[2]/td').text
        except:
            date = "공개일 없음"
        date2.append(date)
        print('2.공개일: ', date)
        f.write('\n'+'2.공개일: '+date)
        
        try:
            contents = driver.find_element(By.XPATH, '//*[@id="content_cont"]/div[2]/div/table[2]/tbody/tr/td/div').text.replace('\n','').replace('Q. 상담내용','').strip()
        except:
            contents = "내용 없음"
        contents2.append(contents)
        print('3.상담내역: ', contents, '\n')
        f.write('\n'+'3.상담내역: '+contents+'\n')
        
        driver.back()
        time.sleep(2)
        
        no += 1
        if no >cnt:
            break
    a += 1
    b = str(a)
    
    try:
        driver.find_element(By.LINK_TEXT, '%s' %b).click()
    except:
        driver.find_element(By.CLASS_NAME, 'next').click()

print('작업완료')
f.close()        
    
import os
n = time.localtime()
s = '%04d-%02d-%02d-%02d-%02d-%02d' %(n.tm_year, n.tm_mon, n.tm_mday, n.tm_hour, n.tm_min, n.tm_sec)
os.makedirs(f_dir+s+'-'+'응답소')
fc_name = f_dir+s+'-'+'응답소'+'\\'+s+'-'+'응답소'+'.csv'
fx_name = f_dir+s+'-'+'응답소'+'\\'+s+'-'+'응답소'+'.xls'

# 데이터 프레임 생성 후 xls , csv 형식으로 저장하기
import pandas as pd
df = pd.DataFrame()
df['번호']=no2
df['제목']=pd.Series(title2)
df['공개일']=pd.Series(date2)
df['상담내역']=pd.Series(contents2)

# xls 형태로 저장하기
df.to_excel(fx_name,index=False, encoding="utf-8" , engine='openpyxl')

# csv 형태로 저장하기
df.to_csv(fc_name,index=False, encoding="utf-8-sig")
print('요청하신 데이터 수집 작업이 정상적으로 완료되었습니다')

href가 javascript같이 되어 있다면 가져와서 사용하는 것이 힘들어 click()을 사용했다.

import os
n = time.localtime()
s = '%04d-%02d-%02d-%02d-%02d-%02d' %(n.tm_year, n.tm_mon, n.tm_mday, n.tm_hour, n.tm_min, n.tm_sec)
os.makedirs(f_dir+s+'-'+'응답소')
fc_name = f_dir+s+'-'+'응답소'+'\\'+s+'-'+'응답소'+'.csv'
fx_name = f_dir+s+'-'+'응답소'+'\\'+s+'-'+'응답소'+'.xls'

자동으로 폴더, 파일을 생성한다.

profile
데이터를 접하는 중

0개의 댓글