实现一个类,抓取一个网站所有页面
实现思路:一边添加url,一边抓取,一直进行下去就可以了,直到列表遍历完成,说明没有新的url可供抓取,即抓取完成。
实际上是图的广度优先遍历。
import urllib.request
import re
from bs4 import BeautifulSoup
class get_all_page_of_site():
'''
参数url是要抓取的网页
'''
def __init__(self,url):
self.__url_list=[]
self.__url_list.append(url)
self.__save_page_number=0
'''
函数功能:根据url获取页面内容,存储位置是loc_dir
返回值:包含页面内容的BeautifulSoup对象
'''
def __get_page(self,url,loc_dir):
try:
#这里使用urllib.urlretrieve(url,file)来也不能简化代码,虽然用它可能不需要关注网页的编码方式,
#保存方便,但是但是它没有返回文件对象,只知道filename,所以还需要打开文件让BeautifulSoup读入
req = urllib.request.Request(url)
f=urllib.request.urlopen(req)
data=f.read()
#使用BeautifulSoup解析html文档时,程序员不用告诉它文档的编码格式
soup=BeautifulSoup(data,"html.parser")
self.__save_page_number+=1
#soup.original_encoding是网页的编码方式,sina新闻大部分是UTF-8,少部分是GBK
file1=open(loc_dir+str(self.__save_page_number)+".html",'w',encoding=soup.original_encoding)
file1.write(str(data.decode(soup.original_encoding)))
file1.close()
#这样不行,因为HTTPResponse只能read()一次,read()之后缓存就清空了。
#return BeautifulSoup(f.read(),"html.parser")
return soup
#下面的异常可以根据需要自行处理
#仍然解析不了的就不解析了
except UnicodeDecodeError:
return None
#如果根据URL,打不开页面,就不再尝试
except urllib.error.URLError:
return None
except TimeoutError:
return None
#如果url语法错误,就不尝试获取页面了,遇到过ValueError: unknown url type
except ValueError:
return None
#这是偷懒的做法
except:
return None
'''
函数功能:找出BeautifulSoup对象里的页面中,匹配 re_str的URL,放入self.__url_list中。
'''
def __add_page_url(self,soup,re_str):
#get_page()可能返回None
if soup is None:
return
for link in soup.find_all('a'):
if re.search(re_str,str(link.get('href'))):
if not (str(link.get('href')) in self.__url_list):
self.__url_list.append(str(link.get('href')))
'''
函数功能:获取所有网页
参数说明:
re_str:是一个正则表达式,用来匹配要爬取的url
loc_dir:指明网页的本地存储位置
max_page:最多抓取多少个网页,-1表示没有限制
'''
def get_all(self,re_str,loc_dir,max_page=100):
#一边向列表尾部添加元素,一边从头开始遍历,不需要维护当前遍历位置
#列表为空了,页面就抓完了。
#列表为空说明最后一个url的页面都抓取了,但是没有新的url产生
for url in self.__url_list:
soup=self.__get_page(url,loc_dir)
print("URL: ",url)
self.__add_page_url(soup,re_str)
print("URL list length:",len(self.__url_list))
print("URL index is:",self.__url_list.index(url))
print("Saved page number:",self.__save_page_number)
if not (max_page==-1 or self.__save_page_number<max_page):
break
'''
使用举例
'''
if __name__=='__main__':
#进行url过滤的正则表达式
#这里抓取url中包含“news.sina.com.cn”并且以“html”结尾的网页
re_str=r".*news\.sina\.com\.cn.*html$"
#抓取到的内容的本地存储位置
loc_dir="sina6/"
#请在这里填写你需要抓取的网站
url='http://news.sina.com.cn/'
site=get_all_page_of_site(url)
site.get_all(re_str,loc_dir)
运行打印:
URL: http://news.sina.com.cn/
URL list length: 240
URL index is: 0
Saved page number: 1
URL: http://slide.news.sina.com.cn/w/slide_1_86523_304209.html
URL list length: 241
URL index is: 1
Saved page number: 2
URL: http://slide.news.sina.com.cn/z/slide_1_64237_303947.html
URL list length: 245
URL index is: 2
Saved page number: 3
保存的文件: