Python爬取百度百科Python相关词条的五十条记录
该项目的目标是爬取百度百科Python词条的五十条记录,从中取出url、标题和相应的摘要,最后输出到一个html文件中,打开文件就可以看到url、标题和相应的摘要
调度程序:
该程序包含了url管理器、html下载器、html分析器和html输出器,他们分别在初试方法中被初始化,在main方法中调用craw()方法,该方法的逻辑为:把传进来的url放到url管理器的待爬取得url集合中,再在待爬取的url集合中取出一条url,用html下载器self.downloader中.download(new_url)方法下载其内容,再用html分析器self.parser中的parse(new_url, html_cont)方法分析内容,取出url、标题、摘要等信息,当爬取到五十条的时候,用html输出器输出成html文档
代码如下:
from baike_spider import html_downloader from baike_spider import html_outputer from baike_spider import html_parser from baike_spider import url_manager class SpiderMain(object): def __init__(self): self.urls = url_manager.UrlManager() self.downloader = html_downloader.HtmlDownloader() self.parser = html_parser.HtmlParser() self.outputer = html_outputer.HtmlOutputer() def craw(self, root_url): count = 1 self.urls.add_new_url(root_url) while self.urls.has_new_url(): try: new_url = self.urls.get_new_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) self.urls.add_new_urls(new_urls) self.outputer.collect_data(new_data) if count == 50: break count = count + 1 except: print 'craw failed' self.outputer.output_html() if __name__ == '__main__': root_url = "https://baike.baidu.com/item/Python/407313" obj_spider = SpiderMain() obj_spider.craw(root_url)
url管理器
该程序初始化了两个集合,一个是已爬取的url集合,一个是待爬取的url集合,并且对外提供四个方法,分别为:add_new_url(self, url)、has_new_url(self)、get_new_url(self)、add_new_urls(self, urls)。这四个方法的功能为:把从网页上爬取的、既不在已爬取的url集合也不在待爬取的url集合的url加入到待爬取的url集合中;has_new_url(self)方法是判断待爬取的url集合中是否还有未爬取的url,返回值为true或者false;get_new_url(self)方法是从待爬取的url中取出一条url,再把该url从待爬取的url集合移动到已爬取的url集合中去;add_new_urls(self, urls)方法是通过调用add_new_url(self, url),筛选从网页爬取下来的url是否需要加入到待爬取的url集合中去。
代码如下:
class UrlManager(object): def __init__(self): self.new_urls = set() self.old_urls = set() def add_new_url(self, url): if url is None: return if url not in self.new_urls and url not in self.old_urls: self.new_urls.add(url) def has_new_url(self): return len(self.new_urls) != 0 def get_new_url(self): new_url = self.new_urls.pop() self.old_urls.add(new_url) return new_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)
html下载器:
该程序对外提供一个方法download(self, url),该方法的作用是去下载传进来的url的网页内容。
代码如下:
import cookielib import urllib2 class HtmlDownloader(object): def download(self, url): if url is None: return None #request = urllib2.Request(url) #request.add_header("user-agent","Mozilla/5.0") cj = cookielib.CookieJar() opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cj)) urllib2.install_opener(opener) response = urllib2.urlopen(url) return response.read()
html分析器:
通过分析,百度百科页面的html发现,其文中链接格式为:<a target="_blank" href="/item/%E8%B7%A8%E5%B9%B3%E5%8F%B0">跨平台</a>,标题的格式为:<dd class="lemmaWgt-lemmaTitle-title">
<h1>Python</h1>,摘要的格式为:<div class="lemma-summary" label-module="lemmaSummary"><div class="para" label-module="para">Python<sup class="sup--normal" data-sup="1">。也就是标题在dd标签class=lemmaWgt-lemmaTitle-title下的h1中,摘要在div的class=lemma-summary中。该程序向外提供一个方法def parse(self, page_url, html_cont),该方法返回值是网页中的url和所需数据,它调用两个内部方法_get_new_urls(self, page_url, soup)和_get_new_data(self, page_url, soup),其中_get_new_urls(self, page_url, soup)方法是爬取页面的url,_get_new_data(self, page_url, soup)方法是爬取所需的数据,比如标题和摘要。
代码如下:
import re import urlparse from bs4 import BeautifulSoup class HtmlParser(object): def parse(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 def _get_new_urls(self, page_url, soup): new_urls = set() links = soup.find_all('a', href=re.compile(r"\/item\/(.*?)")) for link in links: new_url = link['href'] new_full_url = urlparse.urljoin(page_url, new_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 title_node = soup.find('dd', class_="lemmaWgt-lemmaTitle-title").find("h1") res_data['title'] = title_node.get_text() summary_node = soup.find('div', class_="lemma-summary") res_data['summary'] = summary_node.get_text() return res_data
hrml输出器:
该程序对外提供两个方法collect_data(self, data)和output_html(self),collect_data(self, data)方法是收集数据,output_html(self)方法是把收集到的数据输出成html
代码如下:
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): fout = open('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')) fout.write("<td>%s</td>" % data['summary'].encode('UTF-8')) fout.write("</tr>") fout.write("</table>") fout.write("</body>") fout.write("</html>") fout.close()
运行结果如下:
打开输出的html文件如下:
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)