注意:html
1.为了不一个页面被采集两次, 连接去重是很是重要的。
2.写代码以前拟个大纲或画个流程图是很好的编程习惯,这么作不只能够为你后期处理节省
不少时间,更重要的是能够防止本身在爬虫变得愈来愈复杂时乱了分寸。
3.处理网页重定向 正则表达式
•服务器端重定向,网页在加载以前先改变了 URL;
• 客户端重定向,有时你会在网页上看到“10 秒钟后页面自动跳转到……”之类的消息,
表示在跳转到新 URL 以前网页须要加载内容。 编程
服务器端重定向,你一般不用担忧。若是你在用 Python 3.x 版本的 urllib 库,它会自
动处理重定向。不过要注意,有时候你要采集的页面的 URL 可能并非你当前所在页
面的 URL。 服务器
from urllib.request import urlopen from bs4 import BeautifulSoup import re import datetime import random pages = set() #随机数种子 random.seed(datetime.datetime.now()) #获取页面全部内链的列表 def getInternalLinks(bsObj, includeurl): internalLinks = [] #匹配以/开头的字符串,或匹配包括includeurl的字符串,+表示字符串拼接。 for link in bsObj.find_all("a", href=re.compile("^(/|.*" +includeurl+")")): #for link in bsObj.find_all("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 #获取页面内全部外链的列表 def getExternalLinks(bsObj, excludeurl): externalLinks = [] # 找出全部以"http"或"www"开头且不包含当前URL的连接 for link in bsObj.find_all("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 #URL连接切片,为了得到域名 def splitAddress(adress): adressParts = adress.replace("http://", "").split("/") return adressParts #于外链列表中随机选取一条外链 def getRandomExternalLink(startingpage): html = urlopen(startingpage) bsObj = BeautifulSoup(html, "lxml") externalLinks = getExternalLinks(bsObj, startingpage) if len(externalLinks) == 0: internalLinks = getInternalLinks(startingpage) return getExternalLinks(internalLinks[random.randint(0, len(internalLinks)-1)]) else: return externalLinks[random.randint(0, len(externalLinks)-1)] #外链跳转,从一条外链跳转到另外一条 def followExternalOnly(siteurl): externalLink = getRandomExternalLink(siteurl) print("随机外链:", externalLink) followExternalOnly(externalLink) #收集网站内全部外链列表 allExtLinks = set() allIntLinks = set() def getAllExternalLinks(siteurl): html = urlopen(siteurl) bsObj = BeautifulSoup(html, "lxml") internalLinks = getInternalLinks(bsObj, splitAddress(siteurl)[0]) externalLinks = getExternalLinks(bsObj, splitAddress(siteurl)[0]) for link in externalLinks: if link not in allExtLinks: allExtLinks.add(link) print(link) for link in internalLinks: if link not in allIntLinks: allIntLinks.add(link) print("即将获取连接的URL是:"+link) getAllExternalLinks(link) #从互联网采集,从一个外链跳转到另外一个外链 #followExternalOnly("http://oreilly.com") #获取网站全部外链 getAllExternalLinks("http://oreilly.com")
说明:以上代码能够执行两个功能。仅运行followExternalOnly("http://oreilly.com")是从互联网采集,从一个外链跳转到另外一个外链。app
仅运行getAllExternalLinks("http://oreilly.com")能够获取网站全部外链。dom
说一下运行getAllExternalLinks("http://oreilly.com")遇到的问题,发生raise ValueError("unknown url type: %r" % self.full_url),ValueError: unknown url type: '/oscon/oscon-or/schedule'函数
是否是问题出如今获取页面全部内链函数getInternalLinks()的for link in bsObj.find_all("a", href=re.compile("^(/|.*" +includeurl+")")):的部分。为什么要匹配以/开头的URL?网站
不懂,留待之后解决吧。。。但愿我别忘了。。。ui
备注:
url
find()
和find_all()
BeautifulSoup
里的find()
和find_all()
多是你最经常使用的两个函数。借助它们,你能够经过标签的不一样属性轻松地过滤HTML
页面,查找须要的标签组或单个标签。
BeautifulSoup文档地址:http://beautifulsoup.readthedocs.io
find()
函数语法:
find( name , attrs , recursive , string , **kwargs )
find_all()
函数语法:
find_all( name , attrs , recursive , string , **kwargs )
搜索当前tag的全部tag子节点,并判断是否符合过滤器的条件。
name
参数能够查找全部名字为name
的tag,字符串对象会被自动忽略掉。搜索 name
参数的值可使任一类型的过滤器,字符串,正则表达式,列表,方法等。
attrs
参数定义一个字典参数来搜索包含特殊属性的tag
。
经过string
参数能够搜搜文档中的字符串内容,与name
参数的可选值同样。
keyword
参数:若是一个指定名字的参数不是搜索内置的参数名,搜索时会把该参数看成指定名字tag
的属性来搜索。
find_all()
方法返回所有的搜索结构,若是文档树很大那么搜索会很慢。若是咱们不须要所有结果,可使用 limit
参数限制返回结果的数量.效果与SQL
中的limit
关键字相似,当搜索到的结果数量达到limit
的限制时,就中止搜索返回结果。
find 等价于 find_all 的 limit 等于 1 ;
调用tag
的 find_all()
方法时,Beautiful Soup
会检索当前tag
的全部子孙节点,若是只想搜索tag
的直接子节点,可使用参数 recursive=False
。
NavigableString
对象:表示标签里面的文字;Comment
对象:用来查找HTML
文档的注释标签。