我一点点查代码没问题,结果还是NameError: name 'new_urls' is not defined
class UrlManager(object): ##url管理器,用于添加但不重复url,下面有四种
def __init__(self):
self.new_urls=set()
self.old_urls=set()
def add_new_url(self,url): ##向管理器中添加一个新的URL,单个添加
if url is None:
return
if url not in new_urls and url not in old_urls: ##判断一个url既不在待爬去url群里也不在已经爬过的群 ,那么就把它加进待爬去
self.new_urls.add(url)
def add_new_urls(self,urls): ##向管理器中添加一批的URL ,批量添加
if urls is None or len(urls)==0:
return
for url in urls:
self.add_new_url(url)
def has_new_url(self): ##判断是否有新的待爬取得url
return len(self.new_urls)!=0 ##new_urls长度不为0,说明有待爬去的url
def get_new_url(self): ##从url管理器中获取一个url
new_url=self.new_urls.pop() ##pop获取一个的同时移除这个url,
self.old_urls.add(new_url)
return new_url
import urllib.request
class HtmlDownloader(object):
def download(self,url):
if url is None:
return None
response=urllib.request.urlopen(url) ##这里使用了最简单的urllib下载方法,如果要用cookie则需要修改
if response.getcode()!=200:
return None
return response.read()
from bs4 import BeautifulSoup
import re
##urllib.parse模块主要是把url拆分为6部分,并返回元组。并且可以把拆分后的部分再组成一个url。主要有函数有urljoin、urlsplit、urlunsplit、urlparse等。
import urllib.parse
class HtmlParser(object):
def _get_new_urls(self,page_url,soup):
new_urls=set() ##结果存在urls列表里
links=soup.find_all('a',href=re.compile(r"/doc/\d+\.html")) ##"\d+\"用来指代数字串,re.compile实现正则模糊匹配
for link in links:
new_url=link['href']
new_full_url=urllib.parse.urljoin(page_url,new_url) ##new_url按照page_url的格式拼接成全新的url
new_urls.add(new_full_url)
return new_urls
def _get_new_data(self,page_url,soup):
res_data={} ##存放数据
res_data['url']=page_url ##url也放入最终数据中方便使用
##标题右键查看元素,然后右键edit as html得到<h1><span class="title">Python,这个用于确认find内的内容
title_node=soup.find('span',class_="title").find("h1")
res_data['title']=title_node.get_text() ##获取标题数据
##获取方法同上得到<div class="card_content" id="js-card-content"><p>
summary_node=soup.find('div',class_="card_content" )
res_data['summary']=summary_node.get_text() ##获取内容数据
return res_data
def parser(self,page_url,html_cont):
if page_url is None or html_cont is None:
return
soup=BeautifulSoup(html_cont,'html.parser',from_encoding='utf-8')
new_urls=self._get_new_urls(page_url,soup)
new_data=self._get_new_data(page_url,soup)
return new_urls,new_data
class HtmlOutputer(object): ##创建输出器的模块
def __init__(self):
self.datas=[]
def collect_data(self,data): ##收集数据
if data is None:
return
self.datas.append(data)
def output_html(self): ##输出数据写出到html文件中
fout=open('output.html','w') ##建立文件输出对象,output.html是输出文件的命名,w是模式
fout.write("<html>") ##开始标签
fout.write("<body>")
fout.write("<table>")
for data in self.datas:
fout.write("<tr>") ##写一个行的开始标签
fout.write("<td>%s</td>"% data ['url']) ##单元格的内容
fout.write("<td>%s</td>"% data ['title'].encode('utf-8')) ##python默认模式是ascii,如果输出utf-8,就末尾加上.encode('utf-8')
fout.write("<td>%s</td>"% data ['summary'].encode('utf-8')) ##如果没有.encode('utf-8'),有些中文可能识别成乱码
fout.write("</tr>")
fout.write("</table>") ##跟上面相对应的闭合标签
fout.write("</body>")
fout.write("</html>")
fout.close()
class SpiderMain(object): ##创建SpiderMain总调度程序和入口程序
def __init__(self): ##初始化UrlManager、HtmlDownloader等各个模块
self.urls=UrlManager() ##url管理器
self.downloader=HtmlDownloader() ##下载器
self.parser=HtmlParser() ##解析器
self.outpouter=HtmlOutputer() ##输出器
def craw(self,root_url): ##爬虫调度程序
count=1 ##记录当前次数
self.urls.add_new_url(root_url) ##入口url添加进url管理器
while self.urls.has_new_url(): ##有带爬取得url时,启动爬虫循环
try:
new_url=self.urls.get_new_url() ##获取一个url
print('craw %d : %s' % (count,new_url)) ##
html_cont=self.downloader.download(new_url) ##启动下载器下载页面
new_urls,new_data=self.parser.parse(new_url,html_cont) ##解析页面数据,得到新的url列表和新的数据
self.urls.add_new_urls(new_urls) ##url添加进url管理器,这里是urls添加了批量url,上面是单个url
self.outputer.collect_data(new_data) ## 收集数据
if count==1000: ##我们设置爬取1000个页面,达到1000个时就停止
break
count+=1
except: ##有些url已经无法访问或无摘要数据,所以进行异常处理
print("craw failed")
self.outputer.output_html() ##输出收集好的数据
if __name__ =="__main__": ##编写main函数,双下滑线
root_url="https://baike.so.com/doc/1790119-1892991.html" ##设置入口url,就是python360百科网站字符
obj_spider=SpiderMain() ##SpiderMain是总调度程序,前面创建了
obj_spider.craw(root_url) ##用spider启动爬虫