百度AI搜索引擎

时间:2024-02-19 15:40:42

一、爬虫协议

  与其它爬虫不同,全站爬虫意图爬取网站所有页面,由于爬虫对网页的爬取速度比人工浏览快几百倍,对网站服务器来说压力山大,很容易造成网站崩溃。 为了避免双输的场面,大家约定,如果网站建设者不愿意爬虫访问某些页面,他就按照约定的格式,把这些页面添加到 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)))