百度百科基础爬虫

﹥>﹥吖頭↗ 提交于 2019-12-11 13:01:45

出处:Python爬虫开发与系项目实战

作者:范传辉

基础爬虫框架

  1. 爬虫调度器:统筹别的四个模块

  2. URL管理器:维护已经爬取了的url集合和获得新的未爬取的url链接

  3. HTML下载器:从URL管理器中,获取url,并下载html网页

  4. HTML解析器:从下载器中,截取有效数据

  5. 数据存储器:将有效数据进行存储

 

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()

 

5.爬虫调度器SpiderMan.py

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")

 

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!