出处:Python爬虫开发与系项目实战
作者:范传辉
-
爬虫调度器:统筹别的四个模块
-
URL管理器:维护已经爬取了的url集合和获得新的未爬取的url链接
-
HTML下载器:从URL管理器中,获取url,并下载html网页
-
HTML解析器:从下载器中,截取有效数据
-
数据存储器:将有效数据进行存储
1. URL管理器 URLManager.py
-
去重
-
不去重的后果:链接重复容易造成死循环
-
方法:(1)内存去重(2)关系数据库去重(3)缓存数据库去重。
-
在小型中采用set,容易去重
-
URL管理器应有的接口:
方法名称 方法功能 has_new_url() 判断是否有待取的url add_new_url (url) 添加新的url到未爬去的集合中 add_new_urls (urls) get_new_url( ) 获取一个未爬去的url new_url_size( ) 未爬取的url的集合的大小 old_url_size( ) 已爬去的url的集合大小 -
具体代码:
-
class URLManager: def __init__(self): self.new_urls=set() self.old_urls=set() def has_new_url(self,url): return self.new_url_size()!=0 def add_new_url(self,url): if url is None: return if url is not None and url not in self.old_urls: self.new_urls.add(url) def add_new_urls(self,urls): if urls is None or len(urls)==0: return for url in urls: self.add_new_url(url) def get_new_url(self): new_url=self.new_urls.pop() self.old_urls.add(new_url) return new_url def new_url_size(self): return len(self.new_urls) def old_url_size(self): return len(self.old_urls)
2. HTML下载器 HTMLDownloader.py
使用request,只要有一个借口download即可
具体代码:
import requests
class HtmlDownloader:
def download(self,url):
if url is None:
return None
else:
headers={'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.80 Safari/537.36'}
r = requests.get(url,headers=headers)
if r.status_code==200:
return r.content
else:
return None
3.HTML解释器 HtmlParser.py
使用beautifulsoup4,提供parser对外接口
python2中有urllib、urllib2、urlparse,但在python3中这些全部都被整合到了urllib中。urllib和urllib2中的内容整合进了urllib.request模块中,urlparse整合进了urllib.parse中。python3中urllib中还包括response、error和robotparse这些子模块。
快速获取中间文字:在段落中也可以使用 summary.getText()来得到标签以外的文字!
from bs4 import BeautifulSoup
import re
from urllib import parse
class HtmlParser():
def parse(self,page_url,html_cont):
"""
用于解析页面内容,抽取URL和数据
:param page_url: 下载页面的URL
:param html_cont: 下载页面的内容,content
:return: 返回URL和数据
"""
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
def _get_new_urls(self,soup):
"""
抽取新的url集合
:param soup:soup
:return:返回新的url集合
"""
page_url = "https://baike.baidu.com/"
new_urls=set()
links=soup.find_all('a',href=re.compile(r'/item.+'))
for link in links:
new_url=link["href"]
#拼接成完整的url,用到了parse的urljoin功能
full_new_url=parse.urljoin(page_url,new_url)
new_urls.add(full_new_url)
return new_urls
def _get_new_data(self,page_url,soup):
"""
抽取有效数据
:param page_url:下载页面的url
:param soup:
:return:返回有效数据
"""
title = soup.find("dd", attrs={"class": "lemmaWgt-lemmaTitle-title"}).find("h1").getText()
summary = soup.find("div", attrs={"class": "lemma-summary", "label-module": "lemmaSummary"}).getText()
data={}
data["title"]=title
data["summary"]=summary
return data
4.数据存储器DataOutput.py
在这里主要使用将数据输出为html格式. 只能用python一点点往外写
import codecs
#这个库是用来解决编码的问题的
class DataOutput():
def __init__(self):
self.datas = []
def store_data(self, data):
if data is None:
return
self.datas.append(data)
def output_html(self):
fout = codecs.open("baike.html", "w", encoding="utf-8")
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'])
fout.write("<td>%s</td>" % data['summary'])
fout.write("</tr>")
self.datas.remove(data)
fout.write("</table>")
fout.write("</body>")
fout.write("</html>")
fout.close()
from DataOutput import DataOutput
from HtmlDownloader import HtmlDownloader
from HtmlParser import HtmlParser
from URLManager import URLManager
class SpiderMan():
def __init__(self):
self.manager=URLManager()
self.downloader=HtmlDownloader()
self.parser=HtmlParser()
self.data_output=DataOutput()
self.datas=[]
def crawl(self,url):
self.manager.add_new_url(url)
while (self.manager.old_url_size()<=100 and self.manager.has_new_url()):
try:
new_url=self.manager.get_new_url()
content=self.downloader.download(new_url)
new_urls,data=self.parser.parse(new_url,content)
self.manager.add_new_urls(new_urls)
self.data_output.store_data(data)
print("已完成%s"%self.manager.old_url_size())
except Exception as e:
print(e)
self.data_output.output_html()
if __name__ == '__main__':
spider_man=SpiderMan()
spider_man.crawl("https://baike.baidu.com/item/%E7%8E%8B%E9%BB%8E%E4%BC%9F/2826525?fromtitle=%E8%9C%98%E8%9B%9B&fromid=8135722#viewPageContent")
来源:https://www.cnblogs.com/jiaqi77/p/12020805.html