単一ドメインを走査する(URLに日本語を含む場合)

PythonによるWebスクレイピング

PythonによるWebスクレイピング

更新が久しぶりになっちゃいました。

PythonによるWebスクレイピング」を読んでいて気になったところがあったのでまとめました。


気になったところは、

3.1 単一ドメインを走査する の

from urllib.request import urlopen
from bs4 import BeautifulSoup
import datetime
import random
import re

random.seed(datetime.datetime.now())
def getLinks(articleUrl):
    html = urlopen("http://en.wikipedia.org"+articleUrl)
    bsObj = BeautifulSoup(html, "html.parser")
    return bsObj.find("div", {"id":"bodyContent"}).findAll("a", href=re.compile("^(/wiki/)((?!:).)*$"))
links = getLinks("/wiki/Kevin_Bacon")
while len(links) > 0:
    newArticle = links[random.randint(0, len(links)-1)].attrs["href"]
    print(newArticle)
    links = getLinks(newArticle)

です。

これ自体は正常に動きます。ですが、これを日本語版Wikipediaで使おうとするとエラーが起きてしまいました。

理由を考えてみたら……

・日本語版WikipediaのURLは「https://ja.wikipedia.org/wiki/日本語名」となっている

→サンプルコードの

html = urlopen(“http://en.wikipedia.org”+articleUrl)

bsObj = BeautifulSoup(html, “html.parser”)

でエラーが起きてしまう。

なので、urlopenの引数の日本語をURLエスケープさせる必要がある。

個人的にとった対処方法は

url = “https://ja.wikipedia.org/wiki/”+quote_plus(articleUrl,encoding=‘utf-8’)

html = urlopen(url)

bsObj = BeautifulSoup(html,‘html.parser’)

です。

quote関数に関しては、下記を参照。

21.8. urllib.parse — URL を解析して構成要素にする — Python 3.5.2 ドキュメント

ただ、こうやって解決すると、サンプルコードのwhile以下も変更しなきゃいけません。

newArticle = links[random.randint(0, len(links)-1)].attrs[“href”]

newArticle = unquote(newArticle)

newArticle = newArticle.replace(“/wiki/”,‘’)

print(newArticle+“\n”)

links = getLink(newArticle)

getLink関数の引数は、エスケープ前のstr型が欲しいので、unquote関数で元に戻す。

/wiki/を取り除いているのは、日本語部分のみをURLエスケープさせてたいからです。

もっとスマートなやり方があるような気がしますが、それは宿題に。

from urllib.request import urlopen
from urllib.parse import urlparse, quote_plus, unquote
from bs4 import BeautifulSoup
import re
import random
import datetime

random.seed(datetime.datetime.now())


def getLink(articleUrl):
    url = "https://ja.wikipedia.org/wiki/"+quote_plus(articleUrl,encoding='utf-8')
    print(url)
    html = urlopen(url)
    bsObj = BeautifulSoup(html,'html.parser')
    return bsObj.find("div",{"id":"bodyContent"}).findAll("a",href=re.compile("^(/wiki/)((?!:).)*$"))


links = getLink("松本憲生")
while len(links) > 0:
    newArticle = links[random.randint(0, len(links)-1)].attrs["href"]
    newArticle = unquote(newArticle)
    newArticle = newArticle.replace("/wiki/",'')
    print(newArticle+"\n")
    links = getLink(newArticle)

以下、実行結果。

https://ja.wikipedia.org/wiki/%E6%9D%BE%E6%9C%AC%E6%86%B2%E7%94%9F
十五少年漂流記

https://ja.wikipedia.org/wiki/%E5%8D%81%E4%BA%94%E5%B0%91%E5%B9%B4%E6%BC%82%E6%B5%81%E8%A8%98
プリキュアカラフルコレクション

https://ja.wikipedia.org/wiki/%E3%83%97%E3%83%AA%E3%82%AD%E3%83%A5%E3%82%A2%E3%82%AB%E3%83%A9%E3%83%95%E3%83%AB%E3%82%B3%E3%83%AC%E3%82%AF%E3%82%B7%E3%83%A7%E3%83%B3
キャラクターソング

https://ja.wikipedia.org/wiki/%E3%82%AD%E3%83%A3%E3%83%A9%E3%82%AF%E3%82%BF%E3%83%BC%E3%82%BD%E3%83%B3%E3%82%B0
八奈見乗児

https://ja.wikipedia.org/wiki/%E5%85%AB%E5%A5%88%E8%A6%8B%E4%B9%97%E5%85%90
とっても!ラッキーマン

https://ja.wikipedia.org/wiki/%E3%81%A8%E3%81%A3%E3%81%A6%E3%82%82%21%E3%83%A9%E3%83%83%E3%82%AD%E3%83%BC%E3%83%9E%E3%83%B3
テレビせとうち

https://ja.wikipedia.org/wiki/%E3%83%86%E3%83%AC%E3%83%93%E3%81%9B%E3%81%A8%E3%81%86%E3%81%A1
山陽中継局