代码原型来自于《Web Scraping with Python 2ndEdition》P37页的一个案例代码。
代码的功能是根据初始的页面地址抓取该页面中的所有外链接并随机选取一个继续追踪这个外链接指向的新页面,并搜集新页面中的所有外链接随机选取一个后继续追踪。
书中实现该功能的代码整体思路是
- 根据给定的链接抓取该链接指向页面中所有的a标签href属性值,并将href值为外链的提取出来组成列表。外链接的标准是以www或http开头并且不包括从给定的链接中提取出来的netloc信息。
- 页面爬取结束后,如果外链列表中有内容则从中随机选取一个出来,以递归的方式重复步骤1。
- 如果页面爬取结束后,外链列表为空(也就是当前页面一个外链都没有),则重新搜集页面中所有的a标签href属性值,并将href值为内链的提取出来组成列表。内链的标准是以/或者非/的任意内容开头,但链接中包含从给定链接中提取出来的scheme://netloc。
- 页面爬取结束后,从内链列表中随机选取一个内链接出来,以递归的方式重复步骤1。
书中的代码对内链的定义不太准确,一般的内链应该是以/或者..开头,在生成链接的时候可以用scheme://netloc拼接内链后再交由urlopen去访问。如果内链以/开头,则拼接方式就是接单的字符串相加;如果内链以..开头,则拼接的方式可以采用替换。
prefix = f'{urlparse(url).scheme}://{urlparse(url).netloc}'
if link.attrs['href'].startswith('/'):
links.append(prefix+link.attrs['href'] )
else:
links.append(link.attrs['href'].replace('..',prefix) )
修改后的全部代码如下:
from random import randint
import random
from datetime import datetime
from urllib.request import urlopen
from bs4 import BeautifulSoup
from urllib.parse import urlparse
import re
random.seed(datetime.now())
def get_internal_links(bs,url):
prefix = f'{urlparse(url).scheme}://{urlparse(url).netloc}'
links = []
for link in bs.find_all('a',href=re.compile('^(/|\.\.)')):
if link.attrs['href'] is not None and link.attrs['href'] not in links:
if link.attrs['href'].startswith('/'):
links.append(prefix+link.attrs['href'] )
else:
links.append(link.attrs['href'].replace('..',prefix) )
return links
def get_external_links(bs,url):
links = []
for link in bs.find_all('a',href=re.compile('^(https|http|www)((?!'+url+').)*$')):
if link.attrs['href'] is not None:
if link.attrs['href'] not in links:
links.append(link.attrs['href'])
return links
def get_random_link(url):
html = urlopen(url)
bs = BeautifulSoup(html,'html.parser')
domain = urlparse(url).netloc
links = get_external_links(bs,domain)
if len(links)==0:
print(f'没有外链,将寻找新的链接...')
address = f'{urlparse(url).scheme}://{urlparse(url).netloc}'
print('get_random_link address: ',address)
links = get_internal_links(bs,address)
result = links[randint(0,len(links)-1)]
print(f'从{result}中选取一个新的外链进行访问')
return get_random_link(result)
else:
result = links[randint(0,len(links)-1)]
print(f'选中的外链是{result}')
return result
def follow_link(url):
link = get_random_link(url)
follow_link(link)
follow_link('http://shouji.tenaa.com.cn/Mobile/MobileDetail.aspx?code=XSRnDagtFCv8xvg82UmspMQMGLV61AwQ')