百度AI搜索引擎

一、爬虫协议

  与其它爬虫不同,全站爬虫意图爬取网站所有页面,由于爬虫对网页的爬取速度比人工浏览快几百倍,对网站服务器来说压力山大,很容易造成网站崩溃。 为了避免双输的场面,大家约定,如果网站建设者不愿意爬虫访问某些页面,他就按照约定的格式,把这些页面添加到 robots.txt 文件中,爬虫应该主动避免访问这些页面。除此之外,作为爬虫编写者也应该主动控制爬虫访问速度。

  访问 robots 协议的方式是:网站域名+'/robots.txt'。

二、处理爬虫协议

import urllib.robotparser

url = 'https://ai.baidu.com'
rp = urllib.robotparser.RobotFileParser()
rp.set_url(url + '/robots.txt')
rp.read()
info = rp.can_fetch("*", 'https://ai.baidu.com/product/minos')
print(info)

 三、全站爬虫的基本架构

  爬虫从一个 URL 开始访问,通常是网站的域名,并将获得网页中的链接提取出来,去重后放入待访问列表。重复此操作,知道访问完网站内全部网页。

  需要注意的是,全站爬虫通常只爬取网站的内部链接

四、网页链接提取

from requests_html import HTMLSession
session = HTMLSession()
origin = 'https://ai.baidu.com'
r = session.get(origin)
print(r.html.links)

 

五、链接过滤

  使用 urllib 库过滤所有非内部链接,继续运行下面的代码,观察结果:

from urllib.parse import urlparse
from requests_html import HTMLSession
session = HTMLSession()
origin = 'https://ai.baidu.com'
r = session.get(origin)
print(r.html.links)

domain = 'ai.baidu.com'

def is_inner_link(link):
    netloc = urlparse(link).netloc
    return (not netloc) or (netloc == domain)
    
for link in r.html.links:
    print(is_inner_link(link), link)

 

   除了过滤非内部链接外,还需要把已经访问过的链接、爬虫协议不允许的链接 和 你不想访问的链接都过滤掉。

六、百度AI爬虫实现

 

from requests_html import HTMLSession
import urllib.robotparser
from urllib.parse import urlparse

session=HTMLSession()
origin= 'https://www.xuexi.cn/'
domain=urlparse(origin).netloc


def is_inner_link(link):
    netloc=urlparse(link).netloc
    return (not netloc) or (netloc==domain)

visited = []  # 已访问链接列表
unvisited = [origin]  # 待访问链接列表

# 解析爬虫协议
rp = urllib.robotparser.RobotFileParser()
rp.set_url(origin + '/robots.txt')
rp.read()

def add_unvisited(link):
    # 过滤1:判断爬虫协议是否允许
    allow = rp.can_fetch('*', link)
    if not allow:
        return

    # 过滤2:判断是否为内链
    if not is_inner_link(link):
        return

    # 过滤3:去掉非法链接
    path = urlparse(link).path
    if not path.startswith('/'):
        return

    # 过滤4:自定义过滤
    if urlparse(link).path.startswith(('/file', '/docs', '/support', '/forum', '/broad', '/paddlepaddle', '/market',
                                       '/download', '/facekit', '/sdk', '/customer', '/easydl', '//')):
        return

    # 将 /tech/123 转换为 https://ai.baidu.com/tech/123 的形式
    if link.startswith('/'):
        link = origin + link

    # 过滤5:判断是否访问过,或已经添加到待访问列表
    if (link in visited) or (link in unvisited):
        return

    unvisited.append(link)

while len(unvisited):
    link=unvisited.pop()    #用于移除列表中的一个元素
    r=session.get(link)
    visited.append(link)
    if r.html and r.html.links and len(r.html.links):
        for url in r.html.links:
            add_unvisited(url)

    if r.html.find('head title')[0]:
        print(r.html.find('head title')[0].text,link)

print('共爬取{}个链接'.format(len(visited)))

 

posted @ 2019-02-18 16:53  余火灬  阅读(627)  评论(0编辑  收藏  举报