python简单爬虫(二)
上一篇简单的实现了获取url返回的内容,在这一篇就要第返回的内容进行提取,并将结果保存到html中。
一 、 需求:
抓取主页面:百度百科Python词条 https://baike.baidu.com/item/Python/407313
分析上面的源码格式,便于提取:
- 关键词分析:位于class为lemmaWgt-lemmaTitle-title的dd元素的第一个h1标签内
- 简介分析(位于class为lemma-summary的div的text内容)
- 其他相关联的标签的分析(是a标签,且href以/item/开头)
二、抓取过程流程图:

三、分析:
1. 网页下载器:
1.作用:
将互联网上URL对应的网页以HTML形式下载到本地
常用的本地下载器
1、urllib2 Python官方基础模块
2、requests 第三方包,功能更强大
2.urllib下载网页的三种方法
(1)URL传入urllib2.urlopen(url)方法
import urllib2 #直接请求 response = urllib2.urlopen(\'http://www.baidu.com\') #获取状态码,如果是200表示成功 code = response.getcode() #读取内容 cont = response.read()
(2)添加data、http header
将url、data、header传入urllib.Request方法
然后 URLlib.urlopen(request)
import urllib2 #创建Request对象 request = urllin2.Request(url) #添加数据 request.add_data(\'a\'.\'1\') #添加http的header 将爬虫程序伪装成Mozilla浏览器 request.add_header(\'User-Agent\',\'Mozilla/5.0\') #发送请求获取结果 response = urllib2.urlopen(request)
(3)添加特殊情景的处理器
处理用户登录才能访问的情况,添加Cookie
或者需要代理才能访问 使用ProxyHandler
或者需要使用https请求
2.网页解析器
1.作用:
从网页中提取有价值数据的工具
以HTML网页字符串为输入信息,输出有价值的数据和新的待爬取url列表
网页解析器种类
1、正则表达式 将下载好的HTML字符串用正则表达式匹配解析,适用于简单的网页解析 字符串形式的模糊匹配
2、html.parser python自带模块
3、BeautifulSoup 第三方插件
4、xml 第三方插件
原理是解析成DOM树:
2.BeautifulSoup简介及使用方法:
1.简介:
BeautifulSoup:Python第三方库,用于从HTML或XML中提取数据
安装并测试beautifulsoup
方法1:-安装:pip install beautifulsoup4
-测试:import bs4
方法2:pycharm–File–settings–Project Interpreter–添加beautifulsoup4
2.语法介绍:
根据HTML网页字符串可以创建BeautifulSoup对象,创建好之后已经加载完DOM树
即可进行节点搜索:find_all、find。搜索出所有/第一个满足要求的节点(可按照节点名称、属性、文字进行搜索)
得到节点之后可以访问节点名称、属性、文字
如:
<a href=”123.html” class=”aaa”>Python</a>
可根据:
节点名称:a
节点属性:href=”123.html” class=”aaa”
节点内容:Python
创建BeautifulSoup对象:
from bs4 import BeautifulSoup
#根据下载好的HTML网页字符串创建BeautifulSoup对象
soup = BeautifulSoup(
html_doc, #HTML文档字符串
\’html.parser\’ #HTML解析器
from_encoding=\’utf-8\’ #HTML文档编码
)
搜索节点:
方法:find_all(name,attrs,string)
#查找所有标签为a的节点
soup.find_all(\’a\’)
#查找所有标签为a,链接符合/view/123.html形式的节点
soup.find_all(\’a\’,href=\’/view/123.html\’)
soup.find(\’a\’,href=re.compile(\’aaa\’)) #用正则表达式匹配内容
#查找所有标签为div,class为abc,文字为Python的节点
soup.find_all(\’div\’,class_=\’abc\’,string=\’Python\’) #class是Python关键字 避免冲突
由于class是python的关键字,所以讲class属性加了个下划线。
访问节点信息:
得到节点:<a href=”123.html” class=”aaa”>Python</a>
#获取查找到的节点的标签名称
node.name
#获取查找到的节点的href属性
node[\’href\’]
#获取查找到的节点的连接文字
node.gettext()
四、代码实现:
spider.py
# 爬虫的入口调度器 from baike import url_manager, html_downloader, html_parser, html_outputer class SpiderMain(object): def __init__(self): self.urlManager = url_manager.UrlManager() self.downloader = html_downloader.HtmlDownLoader() self.parser = html_parser.HtmpParser() self.outputer = html_outputer.HtmlOutpter() def craw(self,url): count = 1 #定义爬取几个页面 self.urlManager.add_new_url(url) while self.urlManager.has_new_url(): try: # 获取一个url new_url = self.urlManager.get_new_url() # 访问url,获取网站返回数据 html_content = self.downloader.download(new_url) new_urls, new_datas = self.parser.parse(new_url, html_content) self.urlManager.add_new_urls(new_urls) self.outputer.collect_data(new_datas) print(count) if count == 5: break count = count+1 except Exception as e: print("发生错误",e) # 将爬取结果输出到html self.outputer.out_html() if __name__=="__main__": url = \'https://baike.baidu.com/item/Python/407313\' sm = SpiderMain() sm.craw(url)
url_manager.py
# url管理器 class UrlManager(object): def __init__(self): # 定义两个set,一个存放未爬取的url,一个爬取已经访问过的url self.new_urls = set() self.old_urls = set() # 添加一个url的方法 def add_new_url(self,url): if url is None: return None if url not in self.new_urls and url not in self.old_urls: self.new_urls.add(url) # 判断是否还有待爬取的url(根据new_urls的长度判断是否有待爬取的页面) def has_new_url(self): return len(self.new_urls) != 0 # 定义获取一个新的url的方法 def get_new_url(self): if len(self.new_urls)>0: # 从new_urls弹出一个并添加到old_urls中 new_url = self.new_urls.pop() self.old_urls.add(new_url) return new_url # 批量添加url的方法 def add_new_urls(self, new_urls): if new_urls is None: return for url in new_urls: self.add_new_url(url)
html_downloader.py
# 读取网页的类 import urllib.request class HtmlDownLoader(object): def download(self, url): if url is None: return # 访问url response = urllib.request.urlopen(url) # 如果返回的状态码不是200代表异常 if response.getcode() != 200: return return response.read()
html_parser.py
# 网页解析器类 import re import urllib from bs4 import BeautifulSoup class HtmpParser(object): # 解析读取到的网页的方法 def parse(self, new_url, html_content): if html_content is None: return soup = BeautifulSoup(html_content,\'html.parser\',from_encoding=\'utf-8\') new_urls = self.get_new_urls(new_url,soup) new_datas = self.get_new_datas(new_url,soup) return new_urls, new_datas # 获取new_urls的方法 def get_new_urls(self, new_url, soup): new_urls = set() # 查找网页的a标签,而且href包含/item links = soup.find_all(\'a\',href=re.compile(r\'/item\')) for link in links: # 获取到a必去哦啊Ian的href属性 url = link[\'href\'] # 合并url。使爬到的路径变为全路径,http://....的格式 new_full_url = urllib.parse.urljoin(new_url,url) new_urls.add(new_full_url) return new_urls # 获取new_data的方法 def get_new_datas(self, new_url, soup): new_datas = {} # 获取标题内容 title_node = soup.find(\'dd\',class_=\'lemmaWgt-lemmaTitle-title\').find(\'h1\') new_datas[\'title\'] = title_node.get_text() #获取简介内容 summary_node = soup.find(\'div\',class_=\'lemma-summary\') new_datas[\'summary\'] = summary_node.get_text() new_datas[\'url\'] = new_url return new_datas
html_outputer.py
class HtmlOutpter(object): # 构造方法 def __init__(self): self.datas = [] # 收集数据的方法 def collect_data(self, new_datas): if new_datas is None: return # 如果数据不为空就讲数据添加datas集合中 self.datas.append(new_datas) # 输出爬取到的数据到本地磁盘中 def out_html(self): if self.datas is None: return file = open(\'C:\\Users\\liqiang\\Desktop\\实习\\python\\pythonCraw\\out.html\', \'w\', encoding=\'utf-8\') file.write("<html>") file.write("<head>") file.write("<title>爬取结果</title>") # 设置表格显示边框 file.write(r\'\'\' <style> table{width:100%;table-layout: fixed;word-break: break-all; word-wrap: break-word;} table td{border:1px solid black;width:300px} </style> \'\'\') file.write("</head>") file.write("<body>") file.write("<table cellpadding=\'0\' cellspacing=\'0\'>") # 遍历datas填充到表格中 for data in self.datas: file.write("<tr>") file.write(\'<td><a href=\'+str(data[\'url\'])+\'>\'+str(data[\'url\'])+\'</a></td>\') file.write("<td>%s</td>" % data[\'title\']) file.write("<td>%s</td>" % data[\'summary\']) file.write("</tr>") file.write("</table>") file.write("</body>") file.write("</html>")
运行spider.py的主函数:(结果会将提取到的结果保存到html中)
总结:
python的类类似于java,继承object
python的返回值return和return None一样(None类似于java的null关键字)