네이버 블로그

@나성호님 Tidyverse Korea 자연어 처리 발표자료에서 가져옴

크롤링을 위해 필요한 라이브러리를 가져옴

In [1]:
# 필요한 라이브러리를 불러옵니다. 
import requests # HTTP 접속
from bs4 import BeautifulSoup  # 웹페이지 파싱
import re  # 정규표현식
import pandas as pd # 데이터프레임

# 관심 있는 블로그의 URL을 복사하여 붙입니다. 
URL = 'https://sommming.blog.me/221571623395'
# HTTP 요청을 실행합니다. 
res = requests.get(URL)

# HTTP 반응 결과를 확인합니다. 
# HTTP 반응에서 HTML만 따로 출력합니다. 
# 찾는 내용이 없고 <frame>으로 링크가 걸려 있습니다. 
print(f'상태코드: {res.status_code}\n \
        헤더: {res.headers}\n \
        몸통: {res.content.decode("utf-8").strip()}')
상태코드: 200
         헤더: {'Date': 'Mon, 01 Jul 2019 06:37:45 GMT', 'Content-Type': 'text/html; charset=utf-8', 'Transfer-Encoding': 'chunked', 'Connection': 'close', 'Vary': 'Accept-Encoding', 'Cache-Control': 'no-store, no-cache', 'Expires': 'Thu, 01 Jan 1970 00:00:00 GMT', 'Set-Cookie': 'JSESSIONID=F70EA7E740FCFE85F9007F269C2FE6CB.jvm1; Path=/; HttpOnly', 'P3P': 'CP="ALL CURa ADMa DEVa TAIa OUR BUS IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC OTC"', 'Server': 'nxfps', 'Referrer-policy': 'unsafe-url', 'Content-Encoding': 'gzip'}
         몸통: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<meta http-equiv="Pragma" content="no-cache"/>
<meta http-equiv="Expires" content="-1"/>
<meta name="robots" content="noindex,follow"/>
<meta name="referrer" content="always"/>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
<link rel="alternate" type="application/rss+xml" title="기억의 기록" href="http://sommming.blog.me/rss" />
<link rel="wlwmanifest" type="application/wlwmanifest+xml" href="http://sommming.blog.me/NBlogWlwLayout.nhn?blogId=sommming" />
<link rel="shortcut icon" href="//blog.naver.com/favicon.ico" />
<title>기억의 기록 : 네이버 블로그</title>

</head>

<frameset rows="*,0" frameborder="0" framespacing="0">
  <frame id="screenFrame" name="screenFrame" src='https://blog.naver.com/sommming/221571623395?proxyReferer=' scrolling="auto" />
</frameset>
</html>

최종 크롤링 주소를 찾아냅니다.

In [2]:
# BeautifulSoup을 이용하여 HTML을 parsing합니다. 
html = BeautifulSoup(res.content, 'html.parser')
target_URL = html.find('frame').get('src')
target_URL = target_URL + 'https://section.blog.naver.com/BlogHome.nhn'
print(target_URL)
https://blog.naver.com/sommming/221571623395?proxyReferer=https://section.blog.naver.com/BlogHome.nhn

BeautifulSoup을 이용하여 HTML을 parsing합니다.

In [3]:
# HTTP 요청을 실행합니다. 
res = requests.get(target_URL)

# HTTP 반응 결과를 확인합니다. 
print(f'\t URL: {target_URL} \n \
        상태코드: {res.status_code}\n \
        헤더: {res.headers}\n \
        몸통: {res.content.decode("utf-8").strip()}')
	 URL: https://blog.naver.com/sommming/221571623395?proxyReferer=https://section.blog.naver.com/BlogHome.nhn 
         상태코드: 200
         헤더: {'Date': 'Mon, 01 Jul 2019 06:37:45 GMT', 'Content-Type': 'text/html;charset=UTF-8', 'Transfer-Encoding': 'chunked', 'Connection': 'close', 'Cache-Control': 'no-cache', 'Expires': 'Thu, 01 Jan 1970 00:00:00 GMT', 'Set-Cookie': 'JSESSIONID=ECC3C2F249D572DAAB38998662BD8193.jvm1; Path=/; HttpOnly', 'P3P': 'CP="ALL CURa ADMa DEVa TAIa OUR BUS IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC OTC"', 'Access-Control-Allow-Credentials': 'true', 'Access-Control-Allow-Headers': 'accept, content-type', 'Access-Control-Allow-Methods': 'GET, POST', 'Vary': 'Accept-Encoding', 'Content-Encoding': 'gzip', 'Server': 'nxfps', 'Referrer-policy': 'unsafe-url'}
         몸통: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html lang="ko">
<head>
<meta http-equiv="Pragma" content="no-cache"/>
<meta http-equiv="Expires" content="-1"/>
<meta name="robots" content="noindex,follow"/>
<meta name="referrer" content="always"/>
<meta http-equiv="content-type" content="text/html;charset=UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
<link rel="shortcut icon" type="image/x-icon" href="/favicon.ico?2" />
<link rel="alternate" type="application/rss+xml" href="https://rss.blog.naver.com/sommming.xml" title="RSS feed for sommming Blog"/>
<link rel="wlwmanifest" type="application/wlwmanifest+xml" href="https://blog.naver.com/NBlogWlwLayout.nhn?blogId=sommming" />




<title>기억의 기록 : 네이버 블로그</title>
</head>
<script type="text/javascript" src="https://ssl.pstatic.net/t.static.blog/mylog/versioning/Frameset-657805386_https.js" charset="UTF-8"></script>

<script type="text/javascript" charset="UTF-8">
var photoContent="";
var postContent="";

var videoId 	  = "";
var thumbnail 	  = "";
var inKey 		  = "";
var movieFileSize = "";
var playTime 	  = "";
var screenSize 	  = "";

var blogId = 'sommming';
var blogURL = 'https://blog.naver.com';
var eventCnt = '';

var g_ShareObject = {};
g_ShareObject.referer = "https%3A%2F%2Fsection.blog.naver.com%2FBlogHome.nhn";


jsMVC.setController("framesetTitleController", FramesetTitleController);
jsMVC.setController("framesetUrlController", FramesetUrlController);
jsMVC.setController("framesetMusicController", FramesetMusicController);
var oFramesetTitleController = jsMVC.getController("framesetTitleController");
var oFramesetUrlController = jsMVC.getController("framesetUrlController");
var oFramesetMusicController = jsMVC.getController("framesetMusicController");
var sTitle = document.title;

</script>
<style type="text/css">
    html{width:100%;height:100%;}
    body{width:100%;height:100%;margin:0;padding:0;font-size:0;}
    #mainFrame{width:100%;height:99.8%;margin:0;padding:0;border:0;}
    #hiddenFrame{width:0;height:0;margin:0;padding:0;border:0;}
</style>
<body>
    <iframe id="mainFrame" name="mainFrame" allowfullscreen="true" src="/PostView.nhn?blogId=sommming&logNo=221571623395&redirect=Dlog&widgetTypeCall=true&from=section&topReferer=https%3A%2F%2Fsection.blog.naver.com%2FBlogHome.nhn&directAccess=false" scrolling="auto"  onload="oFramesetTitleController.start(self.frames['mainFrame'], self, sTitle);oFramesetTitleController.onLoadFrame();oFramesetUrlController.start(self.frames['mainFrame']);oFramesetUrlController.onLoadFrame()" allowfullscreen></iframe>
    <iframe id="hiddenFrame" name="hiddenFrame" src="/NBlogHidden.nhn?blogId=sommming&musicYN=false" scrolling="no" noresize="noresize"></iframe>
</body>
</html>
In [4]:
# BeautifulSoup을 이용하여 HTML을 parsing합니다. 
html = BeautifulSoup(res.content, 'html.parser')
URL + html.find('iframe').get('src')
Out[4]:
'https://sommming.blog.me/221571623395/PostView.nhn?blogId=sommming&logNo=221571623395&redirect=Dlog&widgetTypeCall=true&from=section&topReferer=https%3A%2F%2Fsection.blog.naver.com%2FBlogHome.nhn&directAccess=false'

블로그글 → 데이터프레임

블로그 제목

In [5]:
%%script false 

# HTTP 요청을 실행합니다. 
res = requests.get(target_URL)

# BeautifulSoup을 이용하여 HTML을 parsing합니다. 
html = BeautifulSoup(res.content, 'html.parser')

# 크롬 개발자도구의 Elements에서 블로그 제목에 해당하는 태그를 찾습니다. 
html.find('span', {'class':'se-fs-fs38'}).get_text()

블로거 닉네임

In [6]:
%%script false 
# 찾은 태그 안에 있는 텍스트만 출력합니다. 
html.find('span', {'class':'nick'}).a.get_text()

작성일자

In [7]:
%%script false 
# 찾은 태그 안에 있는 텍스트만 출력합니다. 
html.find('span', {'class':'se_publishDate'}).get_text()

블로그 본문

In [8]:
%%script false 
text = html.find('div', {'class':'se-main-container'}).get_text()
re.compile('[^가-힣0-9ㄱ-ㅎㅏ-ㅣ^]+').sub(' ', text).strip()

데이터프레임 저장

In [9]:
%%script false 
# 복잡한 구조를 갖는 body를 데이터프레임으로 일괄 변환합니다. 
# 필요한 컬럼만 남깁니다. 
blog = pd.DataFrame(columns = ['head', 'user', 'date', 'text'])

blog = blog.append({'head':html.find('span', {'class':'se-fs-fs38'}).get_text(), 
                    'user':html.find('span', {'class':'nick'}).a.get_text(),
                    'date':html.find('span', {'class':'se_publishDate'}).get_text(),
                    'text':re.compile('\W+').sub(' ', text).strip()},
                   ignore_index = True)

blog