1
1

More than 3 years have passed since last update.

BeautifulSoupでドメイン内リンクを列挙する。

Posted at

実行環境

・macOS High Sierra 10.13.6
・Python 3.8
urllib3 1.26.4
beautifulsoup4 4.9.3
・エディタ Atom
 ・AtomはデフォルトでPythonの実行をサポートしていないので、必要なパッケージをダウンロードする必要がある

はじめに

クローリングしようとしているサイトが、クローリングを許可しているか、禁止しているかについては十分な注意を払うべきである。

あなたは、自社のWebサイトに使用している写真をすべて改めるよう上司の指示を受け、とりあえずのところは、自社Webサイトのリンクをいくつも辿ってドメイン内を東奔西走し、どんな写真が使われていて、あるいは複数のページに重複して使用されている写真がどれだけあって、それぞれ何度使用されているか数えなければならなくなった。
その判断が正しいとして写真のチェックミスがないように、まずはドメイン内のすべてのページをもれなく列挙しよう! と思い立った。

URLを直打ちしないとローマ経由でも辿り着けないような離れ小島のページは考慮に入れないとして、6次の隔たりってわけでもないけどリンクを辿り続けることでドメイン内のすべてのページに辿り着くことができるとするなら、
1.indexページ(ドメインのトップレベルのページ)のURLを与える
2.HTMLの中からリンクを見つけてリストに追加する
3.リストの1つ目のリンクを辿った先のHTMLの中から、まだリストに追加されていないリンクを見つける
4.2-3を繰り返す

と、なんとなく再帰的に使えそうなコードを書けば良さそうだな。と方針が見えてくる。

まずはHTMLを取得するコードから

getHTML.py
#モジュールのインポート
from urllib.request import urlopen
from urllib.error import HTTPError

def getHTML(url):
    try:
        html = urlopen('https://www.▲▲▲.com{}'.format(url))
    except HTTPError as e:
        return None
    return html.read()

ret = getHTML('')
if ret == None:
    print('Returned None')
else:
    print(ret)

まずはここまで。
作った関数を後で再帰的に使いたいので、

getHTML('')

とやっているように、あえて空文字列を渡しておく。
確認のためにhtmlが可読可能な状態で表示されたらOK。

BeautifulSoupを利用してHTMLをパースする

getPages.py
#モジュールのインポート
from urllib.request import urlopen
from urllib.error import HTTPError
from bs4 import BeautifulSoup
import re

def getPages(url):
    global pages
    try:
        html = urlopen('https://www.▲▲▲.com{}'.format(url))
    except HTTPError as e:
        return None
    try:
        bs = BeautifulSoup(html.read(), 'html.parser')
        #ここで正規表現を用いて、画像リンクやcssを排除
        for link in bs.find_all('a',href=re.compile('適当な正規表現')):
            if 'href' in link.attrs:
                if link.attrs['href'] not in pages:
                    newPage = link.attrs['href']
                    pages.add(newPage)
                    getPages(newPage)
    except AttributeError as e:
        return None
    return pages

pages = set()
ret = getPages('')
if ret == None:
    print('Returned None')
else:
    print(ret)

ドメイン内を巡って集めたリンクを格納するために

peges = set()

として集合を作っておく。
まずはBeautifulSoupオブジェクトを作りたいので、

bs = BeautifulSoup(html.read(), 'html.parser')

とする。BeautifulSoupオブジェクトの中から
・a(リンク)タグ
・href属性が内部リンクであるもの
をイテレートしてlinkという変数へ入れるため、

for link in bs.find_all('a',href=re.compile('正規表現')):

というコードを書く。
一度、正規表現による条件を設けずに、1つ目の(ドメイントップの)ページからリンクをすべて書き出す処理を書いて、もしくはブラウザのデベロッパーツールから内部リンクを探せば、条件として書くべき正規表現の検討がつくはずである。

あとは、抽出したリンクからhref属性を取り出して、リンクの集合の中になければそれを集合へ追加し、またそのリンク先を再帰的に調べるということを繰り返す。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1