<jupyter_start><jupyter_text>1. Requests: HTTP for Humans * HTTP와 Request 개론에 대한 부분입니다. 본격적으로 크롤링을 하기 전에 요청이 성공했는지, 즉 크롤링이 가능한 페이지인지 확인해봐야 합니다.<jupyter_code>import json
import requests
google_url = "http://google.co.kr"

# google_url에 requests를 이용해 HTTP GET 요청(Request)을 보냅니다.
# 결과(Response)를 response라는 변수에 저장합니다.
response = requests.get(google_url)
# requests를 보냈을 때 요청이 성공했는지 실패했는지를 response 객체를 통해 알 수 있습니다.

# requests를 통해 보낸 요청이 성공했다면 True, 실패했다면 False가 반환됩니다.
print("Is Request Success: {}".format(response.ok))

# requests를 통해 보낸 요청에 대한 상태 코드가 반환됩니다. 
print("Status Code: {}".format(response.status_code))

# 아래의 raise_for_status() 메소드는 status_code가 400 ~ 600 사이에 속할 때 예외를 발생시킵니다.
response.raise_for_status()
# 이 외에도 response 객체에는 편의를 위한 다양한 기능이 있습니다.
# 아래에 자주 쓰이는 함수의 기능을 간단히 명시해두겠습니다.
# 요청을 보낸 url, 요청 종류에 따라 지금 실행하면 오류가 발생하는 것들도 있기 때문에
# 간단한 설명과 함께 주석을 달아두겠습니다.

# 요청에 사용한 request의 url 정보
# print("요청에 사용한 request의 url: {}".format(response.request.url))

# Response의 Encoding 정보
# print("Response Encoding: {}".format(response.encoding))

# 요청을 통해 결과로 받은 컨텐츠
# response.content

# 요청을 통해 결과로 받은 컨텐츠를 문자열 형태로
# response.text

# 요청을 통해 결과로 받은 컨텐츠를 json으로
# response.json()

print(response.encoding)<jupyter_output>EUC-KR<jupyter_text>2. requests & BeautifulSoup (1) * 이제 실제 웹페이지에 요청을 보내고 그것을 파싱해 보도록 하겠습니다. 먼저 간단하게 구글 홈페이지를 가져옵니다.<jupyter_code>import json
import requests

from bs4 import BeautifulSoup
google_url = "http://google.co.kr"

# google_url에 requests를 이용해 HTTP GET 요청(Request)을 보냅니다.
# 결과(Response)를 response라는 변수에 저장합니다.
response = requests.get(google_url)
# response 변수를 통해 요청이 성공했는지의 여부를 확인합니다.
if response.ok:
    print("response is ok. parse it with BeautifulSoup")
    
    # BeautifulSoup 객체를 이용해 response.text 라는 문자열을 
    # `lxml` 이란 html parser를 이용해 파싱한 뒤 그 결과를 bs라는 변수에 담습니다.
    
    bs = BeautifulSoup(response.text, "lxml") 
else:
    print("response is not ok. response content: {}".format(response.content))    
# .tag_name 을 이용해 HTML 태그에 접근할 수 있습니다.

print(bs.head.title)
# find() 라는 메소드를 이용해 마찬가지로 HTML 태그에 접근할 수 있습니다.

print(bs.head.find("title"))
# find_all() 라는 메소드를 이용해 HTML 태그에 접근할 수 있습니다.
# 결과가 리스트에 담겨 반환됨에 유의합니다.

print(bs.head.find_all("title"))
print(bs.find("link")) 
# 접근한 태그의 href 속성을 가져옵니다.
print(bs.find("link").get("href"))
bs.head.title.get_text()<jupyter_output><empty_output><jupyter_text>3. requests & BeautifulSoup (2) * 네이버 홈페이지에서 실시간 검색어 1-20위 목록을 가져와 보도록 하겠습니다<jupyter_code>import json
import requests

from bs4 import BeautifulSoup
naver_url = "https://www.naver.com/"
response = requests.get(naver_url)
if response.ok:
    print("response is ok. parse it with BeautifulSoup")
    bs = BeautifulSoup(response.text, "lxml")
else:
    print("response is not ok. response content: {}".format(response.content))        
ah_keyword = []
# find_all (다가져올꺼니까!)메소드를 이용해 
#`div` 태그 중 class의 값이 `ah_roll PM_CL_realtimeKeyword_rolling_base` 인 tag를 모두 찾습니다.
rolling_base = bs.find_all("div", {"class" : "ah_roll PM_CL_realtimeKeyword_rolling_base"})
print(rolling_base)
for words in rolling_base:
    # 이 리스트에 있는 값을 순회하며 원하는 값을 찾습니다. `span` 태그 중 class의 값이 `ah_k`인 값을 찾습니다.
    for word in words.find_all("span", {"class" : "ah_k"}):
        ah_keyword.append(word.get_text())
ah_keyword<jupyter_output><empty_output><jupyter_text>* 실습 1 - 네이버 웹소설 크롤링  크롤링할 페이지 : http://novel.naver.com/best/detail.nhn?novelId=583617&volumeNo=4    여기에 들어가서 소설 내용을 크롤링해오고, content라는 변수에 저장합시다.<jupyter_code>import requests
import os

from bs4 import BeautifulSoup
# Write your code here.
target_url="http://novel.naver.com/best/detail.nhn?novelId=583617&volumeNo=4"
response=requests.get(target_url)
print(response.ok)

bs = BeautifulSoup(response.text, "lxml")
content = bs.find("div", {"class" : "detail_view_content ft15"}).p
content
# content를 text 파일로 저장하는 코드입니다.

download_directory = './downloaded_txt/'
file_name = "novel.txt"

directory = os.path.dirname(download_directory)
if not os.path.exists(directory):  # downloaded 폴더 없으면 만들어준다.
    os.makedirs(directory)

with open(download_directory + file_name, "w") as f:
    f.write(content)<jupyter_output><empty_output><jupyter_text>4. JSON Response<jupyter_code>import requests

from bs4 import BeautifulSoup
news_url = "http://sports.news.naver.com/volleyball/news/index.nhn?date=20180130&page=5"
params = {
    'date': 20180130,
    'page': 5
}
response = requests.get(news_url, params=params)
if response.ok:
    print("response is ok. parse it with BeautifulSoup")
    bs = BeautifulSoup(response.text, "lxml")
else:
    print("response is not ok. response content: {}".format(response.content))
print(response.text)
bs.find("div", {"class" : "news_list"}) # 페이지 소스 확인을 통해 알아냈다!
#기사의 정보가 담겨 있는 json 파일의 url을 요청합니다.
news_url = "http://sports.news.naver.com/volleyball/news/list.nhn"
params = {
    'date': 20180129
}

response = requests.get(news_url, params=params)
print(response.text)
if response.ok:
    print("response is ok")
    news_list = response.json()['list']
else:
    print("response is not ok. response content: {}".format(response.content))
for news in news_list:
    print(news['title'])<jupyter_output>대한배구협회, 29일 정기총회 및 배구인의 밤 행사 성황리 마쳐
'배구인의 밤' 성료...장소연 해설위원 1천만원 기탁
<현대건설배구단 모바일 배경화면>
<현대건설배구단 모바일 배경화면>
올스타전 끝낸 이동근 아나운서 "저희도 다시 출격이죠"
中언론 "김연경, 21R 최고 공격수…풍부한 경험 보여줬다"
[KOVO-이슈&포커스] : 집중분석_GS칼텍스편 ①
배구팬 "우리카드, KB손해보험에 승리 예상"
[이슈체크] 5라운드 돌입! 한 주를 돌아보는 V-리그 이슈체크
[배구토토] 팬 71% “우리카드, KB손해보험에 승리”
"우리카드, KB손해보험에 승리"… 배구토토 스페셜 15회차
[KB손해보험] KB Weekly Top3
코트가 반가운 이소영 "소휘가 엄청 늘었던데요?"
국내 최초 프로배구 마케팅 서적 '스포츠마케팅 프로배구편' 출간
프로배구 마케팅 서적 '스포츠마케팅 프로배구편' 출간
[배구토토]배구팬 "우리카드, KB손해보험에 승리"
[배구토토] 스페셜 15회차, "우리카드, KB손해보험에 승리 예상"
KB손해보험 챌린저의 '알.쓸.케.사' 20180125 vs OK저축은행
[삼성화재블루팡스] 블루팡스 아이돌 만들기 대작전
[경기 일정] 1월 30일 도드람 2017~2018 V-리그 5라운드<jupyter_text>5. Crawling Media File<jupyter_code>import os
import requests

from bs4 import BeautifulSoup
img_url = "https://www.google.co.kr/search?dcr=0&source=lnms&tbm=isch&sa=X&ved=0ahUKEwjbp8r-y4bZAhXFfbwKHSYHDAsQ_AUICigB&biw=1224&bih=949#imgrc=_"

params = {
    'q': "박지훈"
}

response = requests.get(img_url, params=params)
if response.ok:
    print("response is ok")
    bs = BeautifulSoup(response.text, "lxml")
else:
    print("response is not ok. response content: {}".format(response.content))
item_list = {}
raw_item_list = bs.find_all("img", {"alt" : "박지훈에 대한 이미지 검색결과"})
raw_item_list
count = 1
for index in raw_item_list:
    item_list[str(count)] = index.get("src")
    count += 1
img_name_format = '{}{}.jpg'
download_directory = './downloaded/'

directory = os.path.dirname(download_directory)       
if not os.path.exists(directory):  # downloaded 폴더 없으면 만들어줌
    os.makedirs(directory)
!pip install Pillow
# PIL은 파이썬 이미지 프로세싱 라이브러리입니다
# Anaconda에서 지원하지 않기 때문에 설치가 안되어 있을 경우 '!pip install Pillow'를 입력해 설치합니다.
from io import BytesIO
from PIL import Image
for item_name, item_url in item_list.items() :
    img_name = img_name_format.format(download_directory, str(item_name))
    response = requests.get(item_url)
    
    if response.ok:
        # 이미지를 저장하는 과정
        with Image.open(BytesIO(response.content)).convert('RGB') as image:
            image.save(img_name)
    else:
        print("This image url({}) has some problems".format(image_url))<jupyter_output><empty_output><jupyter_text>* 실습 2 - 쇼핑몰 이미지 크롤링 크롤링할 페이지 : http://www.laurenhi.com/product/list.html?cate_no=35     이 페이지의 모든 상품 이미지를 크롤링하여, item_list에 저장할 파일 이름, 이미지 소스 url을  의 형태로 저장합시다.         * 대략적인 과정        1. 크롤링할 페이지를 파싱해서 각 이미지의 url을 list에 저장한다.    2. 저장한 list의 url을 for문으로 돌면서 하나씩 저장한다.<jupyter_code>import os
import requests

from bs4 import BeautifulSoup
from io import BytesIO
from PIL import Image
# Write your code here.
img_url = "http://www.laurenhi.com/product/list.html?cate_no=35"


response = requests.get(img_url)
item_list = {}
raw_item_list = bs.find_all("img", {'class' : "thumb"})
if response.ok:
    print("response is ok")
    bs = BeautifulSoup(response.text, "lxml")
else:
    print("response is not ok. response content: {}".format(response.content))
raw_item_list
count = 1
for index in raw_item_list:
    item_list[str(count)] = "http:"+index.get("src")
    count += 1
item_list
img_name_format = '{}{}.jpg'
download_directory = './downloaded/'

directory = os.path.dirname(download_directory)       
if not os.path.exists(directory):  # downloaded 폴더 없으면 만들어줌
    os.makedirs(directory)
for item_name, item_url in item_list.items() :
    img_name = img_name_format.format(download_directory, str(item_name))
    response = requests.get(item_url)
    
    if response.ok:
        # 이미지를 저장하는 과정
        with Image.open(BytesIO(response.content)).convert('RGB') as image:
            image.save(img_name)
    else:
        print("This image url({}) has some problems".format(image_url))
# 사실 이름까지 불러왔어야하는데 이미지만 불러와버렸다
# 이미지를 저장하기 위한 코드입니다.

from io import BytesIO
from PIL import Image
img_name_format = '{}{}.jpg'
download_directory = './downloaded_img/'

directory = os.path.dirname(download_directory)
if not os.path.exists(directory):  # downloaded 폴더 없으면 만들어준다.
    os.makedirs(directory)

item_name_count = 1

for item_name, item_url in item_list.items() :
    img_name = img_name_format.format(download_directory, item_name_count) # 이미지 이름을 1.jpg와 같이 만들어줌
    response = requests.get(item_url)

    if response.ok:
        # 이미지를 저장하는 과정
        with Image.open(BytesIO(response.content)).convert('RGB') as image:
            image.save(img_name)
            item_name_count = item_name_count + 1 
    else:
        print("This image url({}) has some problems".format(image_url))<jupyter_output><empty_output><jupyter_text>6. Using API<jupyter_code># ACCESS_TOKEN 발급 받기
# 1. https://developers.facebook.com/tools/explorer
# 2. 토큰 받기 -> 사용자 엑세스 토큰 받기 -> 권한 선택에서 아무것도 선택하지 않고 액세스 토큰 받기 클릭
# * 이 방식을 통해 발급 받은 ACCESS_TOKEN은 임시 토큰이라 일정 시간이 지나면 expire됩니다.

ACCESS_TOKEN = '<KEY>'   
# YBIGTA 페이스북 페이지 게시물을 가져오겠습니다.
url = 'https://graph.facebook.com/v2.10/{PAGE_NAME}'.format(PAGE_NAME='yonseibigdata')
params = {
    'access_token' : ACCESS_TOKEN
}

#페이스북 페이지를 가져오기 위해서는 해당 페이지의 id가  필요합니다.
#id 가져오기!
response = requests.get(url, params=params).json()
page_id = response['id']
# 미리 설정한 정보를 바탕으로 아래 facebook graph api 호출에 이용할 url을 만들어준다.
URL_FORMAT = 'https://graph.facebook.com/{API_VERSION}/{NODE_ID}/{EDGE_NAME}'


base_url = URL_FORMAT.format(API_VERSION='v2.10', NODE_ID=page_id, EDGE_NAME='feed') # feed는 포스팅을 가져 오겠다는 뜻
# 페이스북 graph-api 중 우리가 이용할 feed에 관한 자세한 정보는 아래에서 참고할 수 있음.
# https://developers.facebook.com/docs/graph-api/reference/v2.10/page/feed

print(base_url)
result = list()

# 기본 설정을 한 뒤 facebook graph api를 이용해 정보를 가져온다.

params = {
    'fields' : 'message,created_time,name,likes.limit(1).summary(true)',
    'access_token' : ACCESS_TOKEN,
    'limit' : 100
}

response = requests.get(base_url, params=params).json()
print(json.dumps(response, indent=4, ensure_ascii=False, sort_keys=True))

# 주요 정보 필드

# created_time: 글 쓴 시간
# id: 글의 id
# likes: 좋아요 누른 사람 정보, 여기서 likes 필드는 likes.limit(1)을 통해 1개만 가져왔다.
# 그 이유는 우리가 필요한 값이 likes.limit(1).summary(true) 을 통해 가져오는 like의 total_count이기 때문이다.
# summary->total_count: 좋아요 전체 count
# message: 글 내용
response.keys()
#페이징 정보는 필요없겠다!!
# 결과 리스트에 최초 호출시 받아온 데이터를 저장해줍니다.
response_data = response['data']
len(response_data)
messages = []
for rsp in response_data:
    try:
        msg = rsp['message']
        like = rsp['likes']['summary']['total_count']
        print('message {}\nlikes : {}\n'.format(msg, like))
        messages.append(msg)
    except:
        continue<jupyter_output>message ※ 최종 합격자 발표 공지 

벌써 2018년 한해가 밝았네요. 
이와 함께 YBIGTA 12기 선발도 완료되었습니다. 

지원자 한분 한분의 능력과 가능성을 소중히 생각하며 선발하다보니 사전에 안내드린 합격자 발표 시간보다 다소 지연되게 되었습니다. 
많이 기다리셨을 지원자분들께 사과의 말씀 드립니다. 

최종 합격자 발표는 늦어도 오늘(5일) 오후 1시 전으로 개별 문자 메시지를 통해 안내드리겠습니다.  

합격 여부와는 관계없이, 지원해주신 한분 한분의 YBIGTA에 대한 관심과 열정에 대해 정말 감사드린다는 말씀 전해드리고 싶습니다. 귀하의 밝은 미래를 항상 응원합니다. 

새해 복 많이 받으세요^^
likes : 8

message ★★공지★★

YBIGTA 12기 모집이 마감되었습니다. 
관심을 갖고 지원해주신 분들께 감사드립니다. 
우선적으로 서류 평가를 거친뒤, 12월 31일(일) 늦은 밤 서류 합격자에 한하여 정확한 면접 일자 및 장소와 시간을 문자로 알려드리겠습니다.

아울러, 오늘 컨퍼런스에 와주신 많은 분들께 감사인사드립니다.
한해 잘 마무리하시고 풍성한 새해 맞이하시길 기원합니다.
감사합니다.
likes : 15

message ★★12기 지원서 마감임박★★

YBIGTA 12기 지원서를 12월 30일 토요일 11:59PM 에 마감합니다.
지원을 희망하시는 분들은 첨부된 링크로 지원서를 작성하신 후 서둘러 제출해주시기 바랍니다. 
아울러, 내일 오후 2시 제 2공학관 B039에서 예정된 [2017 YONSEI BIGDATA CONFERENCE]에도 많은 관심과 참여 부탁드립니다. 

첨부: 지원서 링크 관련
 http://ybigta.com/ 에서 우측 상단 “지원하기” 버튼 클릭!
likes : 12

message [2017 YONSEI BIGDATA CONFERENCE 공지]

본 행사가 이틀 앞으로 다가왔습니다.
예상보다 많은 분들이 신청해주시어 온오프믹스를 통한 신청이 조기마감되었습니다.
현장 접수에 대해 많은 분[...]<jupyter_text>7. Manipulating Header (선택) 접속 시 로그인 정보가 필요한 다음 카페에서 헤더를 조작하여 게시글 가져오기<jupyter_code>img_url = "https://search.naver.com/search.naver"
params = {
    "query" : "박지훈",
    "where" : "image",
    "sm" : "tab_jum"
}

response = requests.get(img_url, params = params)
if response.ok:
    print("response is ok")
    bs = BeautifulSoup(response.text, "lxml")
else:
    print("response is not ok.", response.status_code)

headers = {
    
                "authority" : "search.naver.com",
                "method" : "GET",
                "path" : "/search.naver?where=image&sm=tab_jum&query=%EB%B0%95%EC%A7%80%ED%9B%88",
                "scheme" : "https",
                "accept" : "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8",
                "accept-encoding" : "gzip, deflate, br",
                "accept-language" : "ko-KR,ko;q=0.9,en-US;q=0.8,en;q=0.7",
                "cache-control" : "max-age=0",
                "cookie" : "nx_ssl=2; NNB=YQKGIVKGPFYVU; npic=eAUTziZ3jqZ1EuBiFbNruXZ29DOMnpilGFVTtosn/oKEw1+MQRPt1XezzvHOGtmoCA==; ASID=7dbc7e4b000001614b4203dd0000004e; nid_iplevel=1; nsr_acl=1; _naver_usersession_=vARbro86n9yb7f1Piz5+hQ==; page_uid=TFf8SwpySDVssbvv25sssssstmw-258941",
                "referer" : "https://search.naver.com/search.naver?where=nexearch&sm=top_hty&fbm=1&ie=utf8&query=%EB%B0%95%EC%A7%80%ED%9B%88",
                "upgrade-insecure-requests" : "1",
                "user-agent" : "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36"
    
          }
response = requests.get(img_url, headers= headers, params = params)
response
if response.ok:
    print("response is ok")
    bs = BeautifulSoup(response.text, "lxml")
else:
    print("response is not ok. response content: {}".format(response.content))<jupyter_output>response is ok<jupyter_text>부록 1 - Selenium 사용법<jupyter_code># webdriver 설치하기 : https://chromedriver.storage.googleapis.com/index.html?path=2.32/
# 압축 후 chromedriver.exe 파일의 경로 알아두기
from selenium import webdriver
driver = webdriver.Chrome('chromedriver') #chromedriver의 경로 작성
# 네이버 영화 페이지 접속
base_url = 'http://movie.naver.com/'
driver.get(base_url)
# 검색어 입력창에 검색하고 싶은 영화이름 넣기
search_input_id = 'ipt_tx_srch'
movie_name = '킹스맨: 골드서클'
driver.find_element_by_id(search_input_id).send_keys(movie_name)
# 검색버튼 클릭
search_button_selector = '#jSearchArea > div > button'
driver.find_element_by_css_selector(search_button_selector).click()
# 영화 선택
movie_location_selector = '#old_content > ul:nth-child(4) > li > dl > dt > a'
driver.find_element_by_css_selector(movie_location_selector).click()
# 평점 탭 선택
movie_rating_selector = '#movieEndTabMenu > li:nth-child(5) > a'
driver.find_element_by_css_selector(movie_rating_selector).click()
# 개봉전 페이지 선택
before_open_selector = '#beforePointTab > a'
driver.find_element_by_css_selector(before_open_selector).click()
# 개봉전 평점 페이지 클릭
movie_star_selector = '#beforePointArea > div.sc_area.b_star > div > em'
star_list = driver.find_elements_by_css_selector(movie_star_selector)
star_list
print([[content.text for content in star_list]])
star = ''.join([content.text for content in star_list])
star
# webdriver 끄기
driver.quit()<jupyter_output><empty_output><jupyter_text>부록 2 - 네이버 웹소설 크롤링 심화 크롤링할 페이지 : http://novel.naver.com/best/list.nhn?novelId=583617    여기에 들어가서 '작품 회차'에 있는 모든 소설을 크롤링해오자         * 대략적인 과정        1. 크롤링할 페이지를 파싱해서 각각 소설의 url을 가져와서 list로 저장한다    2. 저장한 list의 url을 for문으로 돌면서 하나씩 요청    3. 각 소설의 url에서 내용만 찾아서 저장    4. 모든 소설의 내용을 하나의 텍스트로 합쳐서 저장<jupyter_code>import requests
import os

from bs4 import BeautifulSoup<jupyter_output><empty_output><jupyter_text>a. 웹페이지에 요청 보내기<jupyter_code>url = "http://novel.naver.com/best/list.nhn"
params = {
    'novelId': 583617
}
response = requests.get(url, params=params)

if response.ok:
    print("response is ok. parse it with BeautifulSoup")
    bs = BeautifulSoup(response.text, "lxml")
else:
    print("response is not ok. response content: {}".format(response.content))<jupyter_output>response is ok. parse it with BeautifulSoup<jupyter_text>b. 각 소설의 url 가져와서 리스트에 저장<jupyter_code>base_url = "http://novel.naver.com/" # 가져온 url 앞에 붙여줄 base_url
novel_url_list = [] # 각 회차의 실제 url이 담길 list

# 각 회차의 url을 가져오자 (추가적인 파싱 필요)
raw_novel_url_list = bs.find("ul", {"class": "list_type2 v3 league_num NE=a:lst"}).findAll("li")

# raw_url_list를 돌면서 실제 url을 가져옴
for raw_novel_url in raw_novel_url_list :
    novel_url = base_url + raw_novel_url.a.get("href")
    novel_url_list.append(novel_url)
    
print(novel_url_list)<jupyter_output>['http://novel.naver.com//best/detail.nhn?novelId=583617&volumeNo=62', 'http://novel.naver.com//best/detail.nhn?novelId=583617&volumeNo=61', 'http://novel.naver.com//best/detail.nhn?novelId=583617&volumeNo=60', 'http://novel.naver.com//best/detail.nhn?novelId=583617&volumeNo=59', 'http://novel.naver.com//best/detail.nhn?novelId=583617&volumeNo=58', 'http://novel.naver.com//best/detail.nhn?novelId=583617&volumeNo=57', 'http://novel.naver.com//best/detail.nhn?novelId=583617&volumeNo=56', 'http://novel.naver.com//best/detail.nhn?novelId=583617&volumeNo=55', 'http://novel.naver.com//best/detail.nhn?novelId=583617&volumeNo=54', 'http://novel.naver.com//best/detail.nhn?novelId=583617&volumeNo=53']<jupyter_text>c. 리스트를 돌면서 각 소설 url로 들어가서 내용만 가져옴<jupyter_code>total_text = '' # 전체 text

for novel_url in novel_url_list :
    response = requests.get(novel_url)
    
    if response.ok:
        print("response is ok for novel_url({}). parse it with BeautifulSoup".format(novel_url))
        crawler = BeautifulSoup(response.text, "lxml")
        content = crawler.find("div", {"class": "detail_view_content ft15"}).p.get_text() # 파싱해서 소설 내용만 가져옴
        total_text = total_text + content # 전체 text에 더해줌
    else:
        print("response is not ok. skip this request. response content: {}".format(response.content))   
        continue

        
print(total_text)<jupyter_output>response is ok for novel_url(http://novel.naver.com//best/detail.nhn?novelId=583617&volumeNo=62). parse it with BeautifulSoup
response is ok for novel_url(http://novel.naver.com//best/detail.nhn?novelId=583617&volumeNo=61). parse it with BeautifulSoup
response is ok for novel_url(http://novel.naver.com//best/detail.nhn?novelId=583617&volumeNo=60). parse it with BeautifulSoup
response is ok for novel_url(http://novel.naver.com//best/detail.nhn?novelId=583617&volumeNo=59). parse it with BeautifulSoup
response is ok for novel_url(http://novel.naver.com//best/detail.nhn?novelId=583617&volumeNo=58). parse it with BeautifulSoup
response is ok for novel_url(http://novel.naver.com//best/detail.nhn?novelId=583617&volumeNo=57). parse it with BeautifulSoup
response is ok for novel_url(http://novel.naver.com//best/detail.nhn?novelId=583617&volumeNo=56). parse it with BeautifulSoup
response is ok for novel_url(http://novel.naver.com//best/detail.nhn?novelId=583617&volumeNo=55). parse it with Beauti[...]<jupyter_text>c. txt 파일로 저장<jupyter_code>download_directory = './downloaded_txt/'
file_name = "total_novel.txt"

directory = os.path.dirname(download_directory)
if not os.path.exists(directory):  # downloaded 폴더 없으면 만들어준다.
    os.makedirs(directory)

with open(download_directory + file_name, "w") as f:
    f.write(total_text)<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.12476703772729562, 'fraction_numerical': 0.023573263486626705, 'mean_word_length': 4.238522427440634, 'pattern_counts': {'":': 2, '<': 57, '<?xml version=': 0, '>': 73, 'https://': 9, 'lorem ipsum': 0, 'www.': 4, 'xml': 13}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 25, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '15', 'dir': 'jupyter-structured-clean-dedup', 'id': '103145', 'license': 'MIT', 'n_tokens_mistral': 10189, 'n_tokens_neox': 11466, 'n_words': 1884, 'path': '_ipynb/.ipynb_checkpoints/2019-11-08-crawling-checkpoint.ipynb', 'repo_name': 'jungsooyun/jungsooyun.github.io', 'size': '20060'}