首页 > 编程语言 >python爬虫如何构建基础爬虫思路

python爬虫如何构建基础爬虫思路

时间:2023-03-21 09:12:57浏览次数:35  
标签:python self URL 爬虫 url 构建 urls new data

对于长期游弋于大数据中的程序来说,正常来说基础爬虫有5个模块,通过多个文件相互间配合,然而实现一个相对完善的爬虫方案,以便于后期做更完善的爬虫方案做准备。

这里目的是爬取200条百科信息,并生成一个html文件,存储爬取的站点,词条,解释。

功能模块

主文件:爬虫调度器,通过调用其他文件中的方法,完成最终功能实现。

其他文件:URL管理器,HTML下载器,HTML解析器,数据存储器。

设计思路

定义SpiderMan类作为爬虫调度器。输入根URL开始爬取数据然后爬取结束。

在爬取过程中,需要获取网页,和解析网页。

解析网页需要HTML解析器,获取网页需要HTML下载器。

解析网页需要解析的数据有:URL,TITLE,CONTEXT等。则需要URL管理器和数据存储器。

主文件设计

主文件添加根URL,然后提取该URL,下载该URL内容。

根据内容,调用解析器:

解析出该URL中的新URL,存入URL管理器;

解析出该URL中的标题,文本等信息,存入数据存储器。

完成后开始下一次。这时URL管理器多出了新的URL,提取出新的URL,下载,解析,不断重复即可。

重复结束以提取出的URL数量超过200则结束。

代码如下:

from BaseSpider.DataOutput import DataOutput
from BaseSpider.HtmlDownloader import HtmlDownloader
from BaseSpider.HtmlParser import HtmlParser
from BaseSpider.UrlManager import UrlManager
class SpiderMan():
    def __init__(self):
        self.manager=UrlManager()
        self.downloader=HtmlDownloader()
        self.parser=HtmlParser()
        self.output=DataOutput()
        
    def crawl(self,root_url):
        self.manager.add_new_url(root_url)
        while(self.manager.has_new_url() and self.manager.old_url_size()<200):
            new_url=self.manager.get_new_url()
            text=self.downloader.download(new_url)
            if text is None:
                print('None text')
                break
            new_urls,data=self.parser.parser(new_url,text)
            self.manager.add_new_urls(new_urls)
            self.output.store_data(data)
            print(self.manager.old_url_size())       
        self.output.output_html()
    
if __name__ == "__main__":
    spider_man=SpiderMan()
    spider_man.crawl("https://baike.baidu.com/item/%E7%BD%91%E7%BB%9C%E7%88%AC%E8%99%AB/5162711?fr=aladdin")
    print('finish')

作为最初的设计,应该允许异常抛出,便于查看程序终止的原因,然后排查错误。

HTML下载器设计

下载网页,返回文本。即可。

import requests
import chardet
class HtmlDownloader(object):
    def download(self,url):
        if url is None:
            return None
        user_agent='Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36 SE 2.X MetaSr 1.0'
        headers={'User-Agent':user_agent}
        r=requests.get(url,headers=headers)
        if r.status_code is 200:
            r.encoding=chardet.detect(r.content)['encoding']
            return r.text
        return None

HTML解析器设计

HTML解析器将下载的文本进行解析,需要解析出的数据有:页面的新URL,页面的新数据文本。

建立相应的解析器,需要打开源码对比,然后进行使用源码分析,使用BeautifulSoup获取所需信息。

为了便于主函数调用或者其他原因,将所有数据通过parser实现返回,其parser分别调用获取URL和获取数据文本的信息

为了处理一些不同网页可能抓取的意外情况导致程序终止,添加了一些判断。

import re
from urllib import parse
from bs4 import BeautifulSoup
class HtmlParser(object):
    def parser(self,page_url,html_cont):
        if page_url is None or html_cont is None:
            return
        soup=BeautifulSoup(html_cont,'lxml')
        new_urls=self.getNewUrls(page_url,soup)
        new_data=self.getNewData(page_url,soup)
        return new_urls,new_data
    
    def getNewUrls(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=parse.urljoin(page_url,new_url)
            new_urls.add(new_full_url)
        return new_urls
    
    def getNewData(self,page_url,soup):
        data={}
        data['url']=page_url
        title=soup.find('dd',class_="basicInfo-item value")
        if title is not None:
            data['title']=title.string
            summary=soup.find('meta',attrs={"name":"description"})
            data['summary']=summary['content']
            return data
        else:
            title=soup.find('meta',attrs={"name":"keywords"})
            if title is not None:
                data['title']=title['content']
                summary=soup.find('meta',attrs={"name":"description"})
                data['summary']=summary['content']
                return data
            else:
                data['title']="ERROR!"
                data['summary']="Please check the url for more information"
                data['url']=page_url
                return data

URL管理器设计

为了避免重复的URL,使用python的set,建立集合初始化。

使用old_urls存储已经访问过的网址,使用new_urls存入将要提取的网址。

然后写好has_new_url等方法,辅助主程序调用。当得到新的URL们时,主程序调用函数将他们存入。

而主程序需要的其他URL管理方案,如提取,数量判定等,也在这里实现。

class UrlManager():
    def __init__(self):
        self.old_urls=set()
        self.new_urls=set()
        pass
    
    def has_new_url(self):
        return self.new_url_size()!=0
    
    def new_url_size(self):
        return len(self.new_urls)
    
    def old_url_size(self):
        return len(self.old_urls)
    
    def get_new_url(self):
        new_url=self.new_urls.pop()
        self.old_urls.add(new_url)
        return new_url
    
    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)
        pass
    
    def add_new_urls(self,urls):
        if urls is None or len(urls) == 0:
            return
        
        for url in urls:
            self.add_new_url(url)
        pass

数据存储器设计

通过HTML解析器获取的数据,通过数据存储器进行存储。

而最终将数据从内存写入到本地磁盘,也在该文件实现。

为了调试美观,建议是先爬取一两个数据做好测试,写好table的宽度设定,加入style='word-break:break-all;word-wrap:break-word;'参数。

import codecs
class DataOutput(object):
    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("<head><meta charset='urf-8'></head>")
        fout.write("<body>")
        fout.write("<table border='1' width=1800  style='word-break:break-all;word-wrap:break-word;'>")
        fout.write("<tr>")
        fout.write("<td width='300'>URL</td>")
        fout.write("<td width='100'>标题</td>")
        fout.write("<td width='1200'>释义</td>")
        fout.write("</tr>")
        for data in self.datas:
            fout.write("<tr>")
            fout.write("<td><a href=%s>%s</a></td>"%(data['url'],data['url']))
            fout.write("<td>%s</td>"%data['title'])
            fout.write("<td>%s</td>"%data['summary'])
            fout.write("</tr>")
        fout.write("</table>")  
        fout.write("</body>")      
        fout.write("</html>")
        fout.close()

最终效果:

当然还有一些数据没有处理好。

标签:python,self,URL,爬虫,url,构建,urls,new,data
From: https://www.cnblogs.com/q-q56731526/p/17238693.html

相关文章

  • python基础
    基本数据类型数字(number)字符串列表字典元组集合循环语句......
  • python基础语法学习
    这里主要记录主要的python语法。1.编码python3默认时UTF-8编码,也可以为源文件指定不同的编码(使用Windows-1252字符集中的字符编码):#-*-coding:cp-1252-*-2.注......
  • python 报错"ValueError: dictionary update sequence element #0 has length 6; 2 is
    python报错"ValueError:dictionaryupdatesequenceelement#0haslength6;2isrequired"现象   分析根据报错分析,应该是字典或格式有问题,检查发现LOGGING......
  • PYTHON银行机器学习:回归、随机森林、KNN近邻、决策树、高斯朴素贝叶斯、支持向量机SV
    全文下载链接:http://tecdat.cn/?p=26219最近我们被客户要求撰写关于银行机器学习的研究报告,包括一些图形和统计输出。该数据与银行机构的直接营销活动相关,营销活动基于电......
  • python学习第一天
    1.python的数据类型(1)python的数据类型不需要单独定义,可以直接对变量赋值而自动判断该类型(我们可以通过type进行查看);(2)一般的数据类型:int(整型),str(字符串类型),bool(布尔类型),fl......
  • python命令
    我们在使用npminstall安装模块的模块的时候,一般会使用下面这几种命令形式:npminstallmoduleName#安装模块到项目目录下npminstall-gmoduleName#-g的意思......
  • python - tesseract-ocr
    1.安装tesseract-ocr下载链接:https://digi.bib.uni-mannheim.de/tesseract/安装后添加环境变量测试安装情况2.安装pytesseractpip3installpytesseract-ihttps......
  • 从0到1构建springboot web应用镜像并使用容器部署
    文章目录​​一、生成镜像的两种方法​​​​1.1、使用commit生成镜像​​​​1.1.1、拉取Centos基础镜像​​​​1.1.2、启动Centos容器并安装Go​​​​1.1.3、commit生成......
  • 使用python来模拟端口被占用的测试场景
    一、测试场景拿到一个运维如软件,做安装部署测试。其中,测试过程中存在一种场景:由于环境清理不干净等原因,导致软件安装部署时,某个组件的端口号被占用,而导致部署失败的情况。......
  • 使用 Python 实现一个 RPC 框架
    1.概述RPC是什么?RPC(RemoteProcedureCallProtocol),RPC是指远程过程调用,比如现在有两台服务器A、B,一个应用部署在A服务器上,想要调用B服务器上应用提供的函数/方......