クローラのコードを読む
クローラをつくるにあたってサンプルコード(https://github.com/REMitchell/python-scraping/blob/master/chapter3/3-crawlSite.py)を読んでみる。
サンプルコードの出典は最後に明記してある。
以下がサンプルコードの全体。
from urllib.request import urlopen from bs4 import BeautifulSoup import re import datetime import random pages = set() random.seed(datetime.datetime.now()) #Retrieves a list of all Internal links found on a page def getInternalLinks(bsObj, includeUrl): internalLinks = [] #Finds all links that begin with a "/" for link in bsObj.findAll("a", href=re.compile("^(/|.*"+includeUrl+")")): if link.attrs['href'] is not None: if link.attrs['href'] not in internalLinks: internalLinks.append(link.attrs['href']) return internalLinks #Retrieves a list of all external links found on a page def getExternalLinks(bsObj, excludeUrl): externalLinks = [] #Finds all links that start with "http" or "www" that do #not contain the current URL for link in bsObj.findAll("a", href=re.compile("^(http|www)((?!"+excludeUrl+").)*$")): if link.attrs['href'] is not None: if link.attrs['href'] not in externalLinks: externalLinks.append(link.attrs['href']) return externalLinks def splitAddress(address): addressParts = address.replace("http://", "").split("/") return addressParts def getRandomExternalLink(startingPage): html = urlopen(startingPage) bsObj = BeautifulSoup(html) externalLinks = getExternalLinks(bsObj, splitAddress(startingPage)[0]) if len(externalLinks) == 0: internalLinks = getInternalLinks(startingPage) return getNextExternalLink(internalLinks[random.randint(0, len(internalLinks)-1)]) else: return externalLinks[random.randint(0, len(externalLinks)-1)] def followExternalOnly(startingSite): externalLink = getRandomExternalLink("http://oreilly.com") print("Random external link is: "+externalLink) followExternalOnly(externalLink) followExternalOnly("http://oreilly.com")
以上のコードを少しずつ区切って読んでいく。まず一番下の行のfollowExternalOnly("http://oreilly.com")はオライリーの公式サイトのURLにfollowExternalOnly関数を適用する。
def followExternalOnly(startingSite): externalLink = getRandomExternalLink("http://oreilly.com") print("Random external link is: "+externalLink) followExternalOnly(externalLink)
followExternalOnly(startingSite):よりオライリーの公式サイトがなにかのはじめとなるURLだということがわかる。externalLink = getRandomExternalLink("http://oreilly.com")でオライリーの公式サイトから関連するリンクをランダムで取得しそれをprintする関数だと推測する。followExternalOnly(externalLink)でこの関数自体を再帰している…と思う。
def getRandomExternalLink(startingPage): html = urlopen(startingPage) bsObj = BeautifulSoup(html) externalLinks = getExternalLinks(bsObj, splitAddress(startingPage)[0]) if len(externalLinks) == 0: internalLinks = getInternalLinks(startingPage) return getNextExternalLink(internalLinks[random.randint(0, len(internalLinks)-1)]) else: return externalLinks[random.randint(0, len(externalLinks)-1)]
getRandomExternalLink(startingPage):よりオライリーの公式サイトがなにかのはじめとなるページだということがわかる。
html = urlopen(startingPage)
bsObj = BeautifulSoup(html)
でページ全体を取り出してBeautifulSoupオブジェクトを作っている。
externalLinks = getExternalLinks(bsObj, splitAddress(startingPage)[0])はbsObjとsplitAddress関数の0番目をgetExternalLinks関数でなんらかの処理をしている。
if len(externalLinks) == 0: internalLinks = getInternalLinks(startingPage) return getNextExternalLink(internalLinks[random.randint(0, len(internalLinks)-1)]) else: return externalLinks[random.randint(0, len(externalLinks)-1)]
ここはもしexternalLinksの長さが0だった場合、getInternalLinks関数でそのスタートページ内のリンクのリストを取り出して…ランダムでその中から1つ選択する…?
def splitAddress(address): addressParts = address.replace("http://", "").split("/") return addressParts
splitAddress関数はaddressを/で分割する関数。address.replace("http://", "")でhttp://を空文字列に置き換えてるようだけどなぜ置き換えてるの…?
def getExternalLinks(bsObj, excludeUrl): externalLinks = [] #Finds all links that start with "http" or "www" that do #not contain the current URL for link in bsObj.findAll("a", href=re.compile("^(http|www)((?!"+excludeUrl+").)*$")): if link.attrs['href'] is not None: if link.attrs['href'] not in externalLinks: externalLinks.append(link.attrs['href']) return externalLinks
getExternalLinks関数はページ内でみつかったhttpまたはwwwではじまるURLを探し出す関数。
def getInternalLinks(bsObj, includeUrl): internalLinks = [] #Finds all links that begin with a "/" for link in bsObj.findAll("a", href=re.compile("^(/|.*"+includeUrl+")")): if link.attrs['href'] is not None: if link.attrs['href'] not in internalLinks: internalLinks.append(link.attrs['href']) return internalLinks
getInternalLinks関数はページ内でみつかった/ではじまるURLを探し出す関数。
冗長な説明になってしまったがコードの意味はわかるようになった。
サンプルコードの出典
『Web Scraping with Python』 Ryan Mitchell、 O'Reilly、 Copyright 2015 Ryan Mitchell、 978-1-491-91029-0、 邦題『PythonによるWebスクレイピング』オライリー・ジャパン、 ISBN978-4-87311-761-4
より3.3 crawlSite.py(https://github.com/REMitchell/python-scraping/blob/master/chapter3/3-crawlSite.py)