出处: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