搭建爬虫框架的基础理论部分

python本来就是一门敏捷、快速的开发语言。就爬虫而言,如果说每次登录一下知乎,或者说每次爬取一些小说都要完成从请求到保存的步骤的话,那么可能你不适合学习python,正所谓人生苦短,我用python。

分析整个请求到保存的过程:不管是自己写的微型框架还是非常受宠的scrapy框架,都需要这几个步骤。麻雀再小都是肉,哦!不对,是麻雀再小,五脏俱全~~~~

先looklook上边这张图自己研究研究。看看是不是这么个理?如果不是的话,欢迎下方吐槽,会及时更改。


步骤一:URL管理    小型爬虫用python自带的set(目的自动去重)  大型的爬虫或者分布式爬虫人家都用redis来管理队列了

所谓URL管理,就拿你去爬去某站妹子图来说吧,一个URL,也就包含那么十几张图,而你需要做的任务就是每次获取下一页的URL并且访问它去爬取对应下一页的图片和下下一页的URL。  这里最容易把人整晕。建议多练练,就能体会到了。

一般来说,这个管理器都是封装好的,自己写框架也就需要自己把结合写好,方便直接调用


步骤二:请求处理Requests

请求库就不说那么多了,像什么urllib,urllib2,urllib3,requests之类的,推荐使用requests,真的是好用。

这个模块可以封装成半成品,根据每次的需求来进行修改,例如需要登录和不需要登录等等


步骤三:页面解析模块,写这个模块之前请仔细掂量掂量自己到底需要的什么数据。

主要使用的解析库 也就re,xpath,beautifulsoup,css-selector  这就够用了。

这个模块是根据每次请求的需求来进行的。

但是强烈建议时刻提醒自己需要哪些数据,因为这样可以帮助你把后边的接口写好,方便schedule来调用


步骤四:数据储存了,这个完全可以高度封装,完全写死一个数据库或者一个数据表。或者就自行配置一下就行了

这个步骤完全是一劳永逸的。


步骤五:你又不是只在一个网页深度晃悠,你总得去子节点找数据吧。就相当于你在百度搜索妹子,你总不可能就在

它找出来的第一个页面晃悠吧,你总得点进去,才能发现新世界的大门。从数据里边分析的子URL那么就又得交给管理器

大哥了,真心累。


说完了以上五个步骤,那么就真刀真枪的干一下  当然还是老掉牙的豆瓣top250,但是是用这个简单的框架来做

1、url管理器

class UrlManager:
    def __init__(self):
        '''
        初始化连个序列  主要是用来去重
        '''
        self.new_url_queue = set()   #待爬取的URL队列
        self.old_url_queue = set()   #已经爬取的URL队列

    def has_new_url(self):
        '''
        判断self.new_url_queue中是否还有未爬取的url
        '''
        if self.new_url_size() != 0:
            print('队列中有未爬去的url')
        else:
            print('没有待爬取的url了')
        return self.new_url_size() != 0

    def get_new_url(self):
        '''
        从队列中拿出url去请求 那么就把这个url放入到old_queue中去
        在set中 pop是对栈首弹出 add是在栈尾插入
        '''
        new_url = self.new_url_queue.pop()
        self.old_url_queue.add(new_url)
        return new_url

    def add_new_url(self, url):
        '''
        往队列中添加新的url
        '''
        print('收到了%s' % url)
        if url is None:
            return
        if url not in self.new_url_queue and url not in self.old_url_queue:
            self.new_url_queue.add(url)
            print('已经添加到队列中,请等待>>>>>>')

    def add_new_urls(self, urls):
        '''
        往队列中添加新的url集合
        '''
        if urls is None or len(urls) == 0:
            return
        for url in urls:
            self.new_url_queue.add(url)

    def new_url_size(self):
        '''
        获取new_url队列的长度
        '''
        return len(self.new_url_queue)

    def old_url_size(self):
        '''
        获取old_url队列的长度
        '''
        return len(self.old_url_queue)

二、请求模块

import requests
from random import choice
from setting import user_agent     # 一个自己搜集的User-Agent库资源

class HTMLDownloader:
    def downloader(self, url):
        if url is None:
            return None
        headers = {'User-Agent': choice(user_agent)}
        response = requests.get(url, headers=headers)
        if response.status_code == 200:
            #print('状态吗是200,请求成功》》')
            response.encoding = 'utf-8'
            return response.text
        return None

三、解析模块(篇幅问题只是解析了每一部电影的URL)

from lxml import etree
import re
from bs4 import BeautifulSoup
'''
三个主要使用的html解析库
'''
class HTMLParse:
    '''
    re在此不进行封装,具体在xpath 和 beautifulsoup中使用
    '''
    def parse_in_xpath(self, html_content):
        '''
        在此填写需要解析的内容
        '''
        html = etree.HTML(html_content)
        each_movie_url = html.xpath(r'//*[@id="wrapper"]/div[1]/div[1]/div[1]/ol/li/div[1]/div[2]/div[1]/a/@href')  # 每一部电影的url
        all_page_urls = html.xpath(r'//*[@id="content"]/div[1]/div[1]/div[2]/a/@href')  # 下一页的url
        return each_movie_url, all_page_urls

    def parse_in_bs4(self):
        '''
        在此填写需要解析的内容
        '''
        return

四、数据存储模块:(写入一个html文件中去)

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, filename):
        fout = codecs.open(filename, 'a+', encoding='utf-8')
        fout.write("<html>")
        fout.write("<head><meta charset='utf-8'/><head>")
        fout.write("<body>")
        fout.write("<table>")
        for data in self.datas:
            fout.write("<tr>")
            fout.write("<td>%s</td>" % data)
            fout.write("</tr>")
            self.datas.remove(data)
        fout.write("</table>")
        fout.write("</body>")
        fout.write("</html>")
        fout.close()



效果截图:








咋说呢,一直在纠结URL队列问题,这次下了个狠心KO了它,做个小笔记,见证自己的成长。

欢迎各位批评指正。







评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值