基础爬虫的五个模块

对书籍《Python爬虫开发与项目实战》147页的理解

部分修改后的原始代码在末尾

五个模块分别是 调度器,url管理器,下载器,解析器,数据导出器

一个感性的认识!image
分为三个相对独立的部分

数据导出的部分是A

是我们的写爬虫的目的,但其本身不影响爬虫运行,你可以用桶接水车运送的水,也可以任由它自由流动

核心部分是B

不停旋转把需要的资源抽出来送到指定地方,关键数据是url 由url管理器,下载器,解析器组成

调度器是C

可以想象是一个人把水车架设好,加初始水让核心部分转起来,之后判断选旋转次数是否达标,及时停止核心部分运行

各模块

下载器:

接受一个url :返回网页内容

简单情况下就是一行代码
return requests.get(url,headers=user_agent).text
但这里是用一个类实现的,这里五个模块都是以类的形式实现 看起来好像是多此一举,这里是为了通用性,一些post方式请求,需要提供的参数要额外生成可能会变得很复杂,但在这个框架下,代码还是很清晰

url管理器:

接受多个url:每次调用返回一个url

爬取到最后新获取到的url会是已爬取url实际不会添加,所以不会出现爬不完的现象

两个集合分别存放添加后还没爬取的链接,爬取后的链接
网页解析后通常会获取多个链接

基本方法有 添加多个url 获取一个url
最初需要添加一个url启动循环,可以以列表形式 添加,但形式上看着还是不舒服,这里又添加了一个方法 添加一个url 基本方法里的添加多个url实现变成了循环调用添加单个url的方

为了方便添加了判断待爬集合是否为空,分别获取两个集合的大小的函数

解析器:

接受网页内容:新爬取url,需要的数据

新url是给循环部分使用的,数据部分给数据存储使用,流到A部分,推荐以字典形式返回

基本犯法 url解析,数据解析

数据导出器:

接受数据:保存数据

基本方法 临时存储变量,数据写入到磁盘

几十条数据可以在爬取结束后调用 写入磁盘函数,数据大可按记录添加次数,每添加10次自动写入磁盘一次,注意写入磁盘后清空原数据变量

调度器:

初始化其他模块,给url添加第一个url

循环中调用各模块中的方法 判断url管理器中已爬取url是否满足要求,及时停止运行

测试运行提示,添加第一个url 设置主站url

形式如下:

https://www.bilibili.com/video/dsadsa

https://www.bilibili.com

改变解析器中url解析规则,可这直接获取所有链接再判断链接的形式是否和video/xxx一样

数据解析部分,可直接返回解释url的结果

数据导出部分可直接输出查查看效果

点击查看代码
import  requests
from lxml import etree

class Url_Manager():
    def __init__(self):
        self.new_url = set()
        self.old_url = set()

    def get_new_url(self):
        url = self.new_url.pop()
        self.old_url.add(url)
        return url

    def add_new_url(self, url):
        if url is None:
            return
        if not url in self.new_url and not url in self.old_url:
            self.new_url.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 has_new_url(self):
        return self.new_url != 0

    def new_urls_size(self):
        return len(self.new_url)

    def old_urls_size(self):
        return len(self.old_url)

class Html_Downloader():
    def download(self,url):
        if url is None:
            return
        user_agent={'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.71 Safari/537.36 Edg/97.0.1072.55' }
        response=requests.get(url,headers=user_agent)
        if response.status_code==200:
            return response.text

class Data_output():
    def __init__(self):
        self.data=[]
        self.conn,self.cur=self.con_db()
        self.cnt=0

    def store_data(self,data):
        if data is None:
            return
        self.data.append(data)
        self.cnt+=1
        if self.cnt%10==0:
            self.out_put_any()

    def out_put_any(self):
        for item in self.data:
            for i in item:
                url,cla,title=i
                sql=f'insert into a values("{title}","{cla}","{url}")'
                try:
                    self.cur.execute(sql)
                except:
                    pass
        self.conn.commit()
        self.data = []
        print(f'out {self.cnt}')

    def con_db(self):
        import sqlite3
        conn=sqlite3.connect(r'data.db')
        cur=conn.cursor()
        try :
            cur.execute('create table a ("title" text,"cla" text,"url" text primary key)')
            conn.execute()
        except:
            print('table exist ')
        return conn,cur

class Html_Parser():
    def parser(self,page_url,content):
        if page_url is None or content is None:
            return
        soup=etree.HTML(content)
        new_urls=self.get_newurls(page_url,soup)
        new_data = self.get_newdata(page_url,soup)
        return new_urls ,new_data

    def get_newurls(self,page_url,html):
        urls=[]
        all_item=html.xpath('//a')
        for item in all_item:
            # title=item.xpath('./a/@title')[0]
            href=item.xpath('./@href')
            if href and'index.php/art/type/id' in href[0]:
                url=page_url+href[0]
                urls.append(url)
        return urls

    def get_newdata(self,page_url,html):
        cla=html.xpath('//div[@class="panel-heading"]/text()')
        if cla:
            cla=cla[0].strip()
        urls=[]
        paras=html.xpath('//tr')
        for item in paras:
            title=item.xpath('./td/a/@title')
            href=item.xpath('./td/a/@href')
            if title and href:
                url=page_url+href[0]
                title=title[0]
                urls.append([url,cla,title])
        data= urls
        return data

class Spider_Man():
    def __init__(self):
        self.manager=Url_Manager()
        self.downloader=Html_Downloader()
        self.parser=Html_Parser()
        self.output=Data_output()

    def crawler(self,root_url):
        page_url='page_url'
        if root_url is None:
            return
        self.manager.add_new_url(root_url)
        while self.manager.has_new_url() and self.manager.old_urls_size() <10:
            try:
                url=self.manager.get_new_url()
                html=self.downloader.download(url)
                urls,data=self.parser.parser(page_url,html)
                self.manager.add_new_urls(urls)
                self.output.store_data(data)
                # {self.manager.old_urls_size()}
                print(f'.',end=' ')
            except:
                print('anything is wrong')
        self.output.out_put_any()

if __name__=='__main__':
    url='url'
    spi=Spider_Man()
    spi.crawler(url)
posted @ 2022-01-24 14:46  caiusxin  阅读(540)  评论(0)    收藏  举报
// 侧边栏目录 // https://blog-static.cnblogs.com/files/douzujun/marvin.nav.my1502.css