什么是爬虫?

网络爬虫(又被称为网页蜘蛛,网络机器人,在FOAF社区中间,更经常的称为网页追逐者),是一种按照一定的规则,自动地抓取万维网信息的程序或者脚本。

 

实现一个爬虫的基本步骤:

1.根据需要构造一个HTTP请求(涵盖指定的rl)

2.解析得到的相应(从HTML中解析出需要的内容)

        a)要从菜单页中获取到每个章节中对应的a标签中的连接

        b)从每个正文页面中获取到指定的div标签中的内容就可以

实现爬虫必须的两个第三方库:

1.requests 这个是用来构造HTTP请求的模块

2.BeautifulSoup4这个是用来分析HTML结构的模块

打开系统命令行 :pip install requests/pip install BeautifulSoup4 来进行下载

第一步:先构造一个HTTP请求,把这个请求发出去并接收到响应:

def open_page(url):
    response = requests.get(url)
    # 手动将程序解析的编码方式设定为 gbk 
    response.encoding = 'gbk'
    if response.status_code != 200:
        print(f"requests get {url} failed! {response.status_code}")
        return ''
    return response.text

在这里我们要注意在打开网页时可能会出现乱码问题:

而出现乱码问题的原因无非是网页的编码方式和程序解析的方式不一致

网页的编码方式大多为GBK

而程序的编码方式大多是UTF-8

而网页的编码方式我们无法决定,因此只能手动规定我们程序的解析方式

发送请求后我们会获得一个当前请求的响应,只有状态码为200,才视为get成功

HTTP状态码:

 

python编写爬虫工具 python爬虫制作_html

 为什么要用爬虫?

很多情况下我们想要看小说或者下载图片时不可避免的网站会充斥各种广告,十分影响阅读体验,类似如下场景(当然这个还算友好,更多的出现性感xx在线发牌这种就会很尴尬),因此我们利用爬虫来进行请求网站并自动提取数据,就可以将小说的内容下载下来。

python编写爬虫工具 python爬虫制作_html_02

当然这样也就意味着爬虫在某些程度上可以称为非法程序,慎用。

 

 首先我们打开一个小说网站搜索“诛仙”:

我们可以得到如下的一个目录:点开一个就可以读取此章节的内容

python编写爬虫工具 python爬虫制作_HTTP_03

 此时鼠标右键点击检查:我们就可以找到与章节对应的源代码

python编写爬虫工具 python爬虫制作_html_04

 并获取每个章节的标签格式为:

python编写爬虫工具 python爬虫制作_.net_05

可以看到每个标签的固定格式为6个数字的a标签,因此可以用find_all方法

第二步:根据内容进行解析,解析每个章节中的url(a标签):

1.先创建一个soup对象

2.找到所有href属性由6个连续的数字组成的url

3.再根据上一步的结果生成所有章节url的列表

# a) 创建一个 soup 对象
    soup = bs4.BeautifulSoup(html, "html.parser")
    # b) 找到所有 href 属性由 6 个连续的数字构成的 url
    charts = soup.find_all(href=re.compile(r'\d{6}.html'))
    # c) 根据上一步的结果生成所有章节的 url 的列表
    url_list = ['https://www.booktxt.net/1_1486/' + item['href'] for item in charts]

第三步:需要解析每个章节的标题和正文:

进入当前章节

python编写爬虫工具 python爬虫制作_.net_06

def parse_detail_page(html):
    '''解析出当前章节的标题和正文'''
    soup = bs4.BeautifulSoup(html, "html.parser")
    title = soup.find_all(class_='bookname')[0].h1.get_text()
    content = soup.find_all(id='content')[0].get_text()
    return title, content

第四步:我们需要创建一个文件来保存当前获取到的小说内容

def write_file(title, content):
    with open("tmp.txt", 'a', encoding='gbk', errors='ignore') as f:
        f.write(title + '\n' + content + '\n\n\n')

第五步:综合以上内容进行运行

def run():
    url = 'https://www.booktxt.net/1_1486/'
    # 1. 打开入口页面, 并分析出其中的所有详情页的 url
    html = open_page(url)
    url_list = parse_main_page(html)
    # 2. 遍历详情页的 url, 依次分析每个详细内容页
    for url in url_list:
        print("crawler url:", url)
        detail_html = open_page(url)
        title, content = parse_detail_page(detail_html)
        write_file(title, content)
        time.sleep(5)
    print("crawler done!")

run()

可以获得以下内容:

python编写爬虫工具 python爬虫制作_HTTP_07

python编写爬虫工具 python爬虫制作_python编写爬虫工具_08

这里要注意一点就是反爬虫的问题:

我在多次运行的情况下就出现了下面的报错:

python编写爬虫工具 python爬虫制作_python编写爬虫工具_09

太高频率的访问网页,网页会将这个操作理解为恶意访问网页。。。。

 目前的反爬虫手段大致为以下四种:

1.按IP来封禁

换了一个热点得以解决

2.按访问频率封禁

可以在程序中添加一个延时程序,避免过高频率

time.sleep(5)

3.按UA来封禁 伪装UA

HTTP请求的 header部分中添加一个比较接近浏览器的UA

参考抓包结果:

python编写爬虫工具 python爬虫制作_.net_10

headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36'
    }
    response = requests.get(url, headers=headers)

4.按cookie来封禁

 

附源码:

'''
实现一个爬虫程序, 抓取诛仙小说. 把小说内容保存到一个文件之中
入口地址 https://www.booktxt.net/1_1486/
'''
import requests
import bs4
import re
import time

# 1. 先构造一个 HTTP 请求, 把这个请求发送出去获取到响应
# 既能打开菜单页, 也能打开内容页. 
def open_page(url):
    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36'
    }
    response = requests.get(url, headers=headers)
    # 手动将程序解析的编码方式设定为 gbk 
    response.encoding = 'gbk'
    if response.status_code != 200:
        print(f"requests get {url} failed! {response.status_code}")
        return ''
    return response.text

def test1():
    print(open_page('https://www.booktxt.net/1_1486/'))

# 2. 根据内容来进行解析
# 解析出每个章节的 url (a 标签中解析)
def parse_main_page(html):
    # a) 创建一个 soup 对象
    soup = bs4.BeautifulSoup(html, "html.parser")
    # b) 找到所有 href 属性由 6 个连续的数字构成的 url
    charts = soup.find_all(href=re.compile(r'\d{6}.html'))
    # c) 根据上一步的结果生成所有章节的 url 的列表
    url_list = ['https://www.booktxt.net/1_1486/' + item['href'] for item in charts]
    return url_list

def test2():
    html = open_page('https://www.booktxt.net/1_1486/')
    print(parse_main_page(html))

# test2()
def test3():
    # 验证一下使用 open_page 来打开小说详情页的内容
    print(open_page('https://www.booktxt.net/1_1486/491531.html'))

#test3()

def parse_detail_page(html):
    '''解析出当前章节的标题和正文'''
    soup = bs4.BeautifulSoup(html, "html.parser")
    title = soup.find_all(class_='bookname')[0].h1.get_text()
    content = soup.find_all(id='content')[0].get_text()
    return title, content

def test4():
    html = open_page('https://www.booktxt.net/1_1486/491534.html')
    # print(html)
    title, content = parse_detail_page(html)
    print("title:", title)
    print("content:", content)

# test4()
def write_file(title, content):
    with open("tmp.txt", 'a', encoding='gbk', errors='ignore') as f:
        f.write(title + '\n' + content + '\n\n\n')

# 把刚才的几个步骤拼装在一起
def run():
    url = 'https://www.booktxt.net/1_1486/'
    # 1. 打开入口页面, 并分析出其中的所有详情页的 url
    html = open_page(url)
    url_list = parse_main_page(html)
    # 2. 遍历详情页的 url, 依次分析每个详细内容页
    for url in url_list:
        print("crawler url:", url)
        detail_html = open_page(url)
        title, content = parse_detail_page(detail_html)
        write_file(title, content)
        time.sleep(5)
    print("crawler done!")

run()