【Python】note記事のバックアップ|Webスクレイピングプログラムの作成例 | ムノログ 合同会社ムジンケイカクプロのITノウハウブログ
Pythonと機械学習

【Python】note記事のバックアップ|Webスクレイピングプログラムの作成例

python Pythonと機械学習

Webスクレイピングとは?

様々なWebサイトから情報を抽出・取得する技術です。
Googleの検索エンジンが、あなたのサイトを巡回して情報を取得していくのも、Webスクレイピングといっていいでしょう、きっと。
Webサイトの特定の情報を自動で取得し一覧化や分析までを助ける技術がスクレイピングと、ここでは紹介させていただきます。

スクレイピングのご注意

ウェブスクレイピング – Wikipedia

基本的に他のサイトに負荷をかけます。
そのため利用規約などで明確にスクレイピングを禁止しているサイトへのスクレイピング行為は、法的にも問題があります。
またスクレイピング対策をしているサイトへ無理やりスクレイピングをするのも、悪質な行為とご認識ください。

スクレイピングの依頼でよくあるご要望

どこかのサイトに自動でログインし、内容を監視する。
ある条件でショップのデータを集める。
特定サイトへの自動入力と自動操作。

note記事のWebスクレイピングをする理由

note記事のリライティングをしたい。
そのためにnoteの記事タイトル一覧が欲しい。

note記事のWebスクレイピング|実際のプログラミング

from google.colab import drive 
drive.mount('/content/drive/')
%cd "drive/My Drive/note_backup"

!apt-get update
!apt install chromium-chromedriver
!cp /usr/lib/chromium-browser/chromedriver /usr/bin
!pip install selenium

from bs4 import BeautifulSoup

from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.common.exceptions import TimeoutException
from selenium.webdriver.support import expected_conditions as ec
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By


import numpy as np
import pandas as pd
pd.set_option('display.max_columns', 500)
pd.set_option('display.max_rows', 500)

import csv

from datetime import datetime
from time import sleep
import os, time

import json
import requests

import math

urllist = []
urllist = ['ここを自分のダッシュボードのURLに']
print(urllist)

#######自分の公開記事は何記事かをpost_numに入れる#######
post_num = 200
post_math = math.ceil(post_num/6)

urllist = []
df_concat = pd.DataFrame(index=[])

for i in range(1,post_math):
   url = 'https://note.com/api/v2/creators/mkp_consulting/contents?kind=note&page=' + str(i) + '&disabled_pinned=false'
   urllist.append(url)

def DF_MAKE(urllist):

   html = ""
   options = webdriver.ChromeOptions()
   options.add_argument('disable-infobars')
   options.add_argument('--no-sandbox')
   options.add_argument('--headless')
   options.add_argument('--window-size=1024,768')
   user_agent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Safari/537.36"
   options.add_argument(user_agent)
   
   driver = webdriver.Chrome(options=options);
   driver.implicitly_wait(30)
   driver.set_page_load_timeout(30)

   j = 0
   while j < 9:
       try:
           driver.get(urllist)
           print("The page was loaded")
       except TimeoutException:
           j = j + 1
           print("Timeout, Retrying... (%(j)s/%(max)s)" % {'j': j, 'max': 9})
           time.sleep(10)
           continue
       else:
           break
           
   print("-----------------------------------------------------------------")

   html = driver.page_source
   Tag = driver.find_element_by_tag_name('pre').get_attribute('innerText')
   json_dict = json.loads(Tag)
   df = pd.DataFrame(json_dict["data"]["contents"])
     
   if df.empty:
       return


   return df


for i in range(len(urllist)):

   sleep(5)
   
   print(i,len(urllist),urllist[i])

   df = DF_MAKE(urllist[i])
   
   if df.empty:
       break       
   else:
       df_concat = pd.concat([df_concat,df])

df_concat.to_csv('note_list_backup.csv')
print('end')

note記事のWebスクレイピング|準備

▽GoogleDriveにフォルダ作成

GoogleDrive直下にnote_backupというフォルダがある前提です。

▽noteダッシュボードのURL

自身のnoteダッシュボードのURLを取得しておいてください。

▽note記事の公開記事数を入れる

Webスクレイピングの動作後の結果

GoogleDriveのnote_backupフォルダに、CSVファイルが作成されます。

Colaboratory環境【ファイル添付有】【記事一覧取得補正版】

note公開記事の総数取得用pythonコード。
単純にJSONファイルを呼び出して、総数が格納されているところへアクセス。

def func_totalCount(url_id):
 import requests
 import json

 #JSONの取得 
 json_res = requests.get('https://note.com/api/v2/creators/' + url_id + '/contents?kind=note&page=1&disabled_pinned=false')
 data = json_res.json()
 print(json.dumps(data, indent=4))

 json_dict = json.dumps(data, indent=4)

 totalCount = data['data']['totalCount']
 print(totalCount)
 return totalCount

note記事URLの作成

def num_kiji(url_id,totalCount): 
 #######自分の記事は何記事#######
 post_math = math.ceil(totalCount/6)

 urllist = []
 df_concat = pd.DataFrame(index=[])

 for i in range(1,post_math):
     url = 'https://note.com/api/v2/creators/' + url_id + '/contents?kind=note&page=' + str(i) + '&disabled_pinned=false'
     urllist.append(url)
 return urllist

注意

自分のnoteダッシュボードからIDらしきものを入れる。
たまに失敗するが、再度、時間間隔を開けて実行すると成功する。
あまりいたずらに作動させてしまうと、note側に負荷がかかります。

url_id = 'mkp_consulting'
print(url_id)

ここまでのプログラム全体

私自身がプログラマではないため、修正点やおかしなところは多々あるかと思いますが、以下で共有公開しておりますのでご参考になさってください。

Google Colaboratory
from google.colab import drive 
drive.mount('/content/drive/')
%cd "drive/My Drive/note_backup"

!apt-get update
!apt install chromium-chromedriver
!cp /usr/lib/chromium-browser/chromedriver /usr/bin
!pip install selenium

from bs4 import BeautifulSoup

from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.common.exceptions import TimeoutException
from selenium.webdriver.support import expected_conditions as ec
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By

import numpy as np
import pandas as pd
pd.set_option('display.max_columns', 500)
pd.set_option('display.max_rows', 500)

import csv

from datetime import datetime
from time import sleep
import os, time

import json
import requests

import math

url_id = 'mkp_consulting'#@param {type:"string"}

def DF_MAKE(urllist,totalCount):

    html = ""

    j = 0
    while j < 9:
        try:
            driver.get(urllist)
            print("The page was loaded")
        except TimeoutException:
            j = j + 1
            print("Timeout, Retrying... (%(j)s/%(max)s)" % {'j': j, 'max': 9})
            time.sleep(10)
            continue
        else:
            break
            
    print("-----------------------------------------------------------------")

    html = driver.page_source
    Tag = driver.find_element_by_tag_name('pre').get_attribute('innerText')
    json_dict = json.loads(Tag)
    
    df = pd.DataFrame(json_dict["data"]["contents"])
      
    if df.empty:
        return


    return df

def func_totalCount(url_id):

  #JSONの取得
  json_res = requests.get('https://note.com/api/v2/creators/' + url_id + '/contents?kind=note&page=1&disabled_pinned=false')
  data = json_res.json()
  print(json.dumps(data, indent=4))

  json_dict = json.dumps(data, indent=4)

  totalCount = data['data']['totalCount']
  print(totalCount)
  return totalCount

def num_kiji(url_id,totalCount): 
  #######自分の記事は何記事#######
  post_math = math.ceil(totalCount/6)

  urllist = []
  df_concat = pd.DataFrame(index=[])

  for i in range(1,post_math):
      url = 'https://note.com/api/v2/creators/' + url_id + '/contents?kind=note&page=' + str(i) + '&disabled_pinned=false'
      urllist.append(url)
  return urllist

totalCount = func_totalCount(url_id)
urllist = num_kiji(url_id,totalCount)

df_concat = pd.DataFrame()

options = webdriver.ChromeOptions()
options.add_argument('disable-infobars')
options.add_argument('--no-sandbox')
options.add_argument('--headless')
options.add_argument('--window-size=1024,768')
user_agent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Safari/537.36"
options.add_argument(user_agent)

driver = webdriver.Chrome(options=options);
driver.implicitly_wait(30)
driver.set_page_load_timeout(30)

for i in range(len(urllist)):

    sleep(5)
    
    print(i,len(urllist),urllist[i])

    df = DF_MAKE(urllist[i],totalCount)
    
    if df.empty:
        break   
    elif df_concat.empty:
        df_concat = df 
    else:
        df_concat = pd.concat([df_concat,df])

df_concat.to_csv('note_list_backup.csv')
print('end')


以下ファイルに関してはノークレームノンサポートですが、質問あれば随時お問い合わせからご連絡ください。
わかる範囲でお答えます。

不完全な点|記事の総数取得部分を修正

予定