반응형
안녕하세요~ 이번엔 제가 지난 학기 학교 과제로 수행했던 CNN 기사를 웹스크래핑했던 코드를 공유하고자 합니다. 다음이 전반적인 과제 내용입니다.
import requests
from bs4 import BeautifulSoup
import pandas as pd
import os
import natsort
import re
# 폴더 안에 있는 cnn html파일 읽어들이기
# html 파일 구조가 동일하지 않고 총 2가지로 분류되기 때문에 try와 except 활용
path = './cnn/'
file_list = os.listdir(path)
file_list = natsort.natsorted(file_list,reverse=False)
df = pd.DataFrame(columns=['filename', 'date', 'headline', 'text'])
for i in file_list:
filename = i[:5]+i[5:].split('.')[0].zfill(3)
url = path + i
try:
with open(url, 'rt', encoding='UTF-8') as fp:
soup = BeautifulSoup(fp, 'html.parser')
title = soup.find(class_ = 'pg-headline').get_text() #headline
inputstr = ""
for i in soup.findAll(class_="zn-body__paragraph"):
if len(i['class']) == 2:
if i['class'][1] !='zn-body__footer':
inputstr += (i.get_text() + " ")
else:
inputstr += (i.get_text() + " ")
text = inputstr
date_or = soup.find(class_ = 'update-time').get_text()
date = str(date_or)[24:].strip()
except Exception:
with open(url, 'rt', encoding='UTF-8') as fp:
soup = BeautifulSoup(fp, 'html.parser')
title = soup.find(class_ = 'article-title speakable').get_text() #headline
date_to = soup.find(class_ = 'cnnDateStamp').get_text()
pattern = ':'
date_ch = re.split(pattern, date_to)
date = date_ch[0].strip()
bodies = soup.findAll('h2', 'speakable')
bodies += soup.select('#storytext > p')
inputstr = ""
for body in bodies:
if body.get_text().find('--') != 1:
inputstr += (body.get_text() + " ")
text = inputstr
df.loc[len(df)] = [filename, date, title, text]
# 순서대로 정리 및 csv 파일로 변환
df = df.sort_values('filename').reset_index(drop=True)
df.to_csv('201419191_cnn.csv', sep=',', index=True, encoding='UTF-8')
df
# 데이터 정제(소문자, 각종 기호 및 의미 없는 반복 구조 제거, 문장 변환)
import re
from nltk.tokenize import sent_tokenize
def data_cleaning():
df = pd.read_csv('201419191_cnn.csv')
df['text'] = df.text.apply(lambda x: x.split('(CNN)')[1] if len(x.split('(CNN)'))==2 else x.split('(CNN)')[0])
df['text'] = df['text'].str.lower()
df['text'] = df['text'].apply(lambda x: re.sub('[!|"|#|$|%|\'|&|(|)|*|+|,|\-|/|:|;|<|=|>|?|@|\[|\]|^|_|`|{|\||}|~]', '', x))
df['text'] = df.text.apply(lambda x: sent_tokenize(x))
df.to_csv('201419191_cnn_cleaned.csv')
return df
df = data_cleaning()
df
# 문장 수 출력
from ast import literal_eval
def sent_count():
df = pd.read_csv('201419191_cnn_cleaned.csv')
df.text = df.text.apply(literal_eval)
df['sent_count'] = df.text.apply(lambda x: len(x))
return df
df = sent_count()
df
# 단어 토크나이즈
import nltk
from nltk import RegexpTokenizer
def content_token_count():
tokenizer = RegexpTokenizer("\s+", gaps=True)
df['content'] = df.text.apply(lambda x: " ".join(x))
df['word'] = df.content.apply(lambda x: tokenizer.tokenize(x))
df['word_count'] = df['word'].apply(lambda x: len(x))
return df
df = content_token_count()
df
# lemmatization 실행
from nltk import pos_tag
from nltk.stem import WordNetLemmatizer
import numpy as np
def lemma_type_count(x):
keys, values = np.unique(x, return_counts=True)
return list(zip(keys, values))
def lemmatize():
wnl = WordNetLemmatizer()
df['lemma'] = df.word.apply(lambda x: pos_tag([wnl.lemmatize(i) for i in x])) # pos_tag가 아니라 lemma 자체 전체 갯수를 구해야함..
df['lemma(type)'] = df.lemma.apply(lambda x: [t[1] for t in x])
df['lemma_count'] = df['lemma(type)'].apply(lemma_type_count)
return df
df = lemmatize()
df
위의 출력값이 최종 lemmatization한 결과입니다! 약 반년이 지난 지금 다시 정리해보려니 또 어렵네요... 역시 코드는 계속 공부해야 하나 봅니다 ㅠㅠ
728x90
반응형
'문돌이 존버 > 코딩연습' 카테고리의 다른 글
git 기본 지식 쌓기(2) (0) | 2020.09.17 |
---|---|
파이썬 웹크롤링(web-crwaling) 파헤치기! feat. BeautifulSoup, Selenium (0) | 2020.07.18 |
git 기본 지식 쌓기(1) (0) | 2020.07.11 |
동적 페이지 수집(Instagram) using Selenium (0) | 2020.01.27 |
Python을 이용한 네이버 뉴스 댓글 크롤링 (2) | 2020.01.24 |