python网络爬虫_Python教程:网络爬虫快速入门实战解析

建议: 请在电脑的陪同下,阅读本文。本文以实战为主,阅读过程如稍有不适,还望多加练习。

网络爬虫简介

网络爬虫,也叫网络蜘蛛(Web Spider)。它根据网页地址(URL)爬取网页内容,而网页地址(URL)就是我们在浏览器中输入的网站链接。比如:https://www.baidu.com/,它就是一个 URL。

在讲解爬虫内容之前,我们需要先学习一项写爬虫的必备技能: 审查元素(如果已掌握,可跳过此部分内容)

1、审查元素

在浏览器的地址栏输入 URL 地址,在网页处右键单击,找到检查。(不同浏览器的叫法不同,Chrome 浏览器叫做检查,Firefox 浏览器叫做查看元素,但是功能都是相同的)

235291907498a1f62381882064068c6d.png
2cd5bbaee0abea29df1034567371bc3a.png

Python3 网络爬虫快速入门实战解析

我们可以看到,右侧出现了一大推代码,这些代码就叫做 HTML。什么是 HTML?举个容易理解的例子: 我们的基因决定了我们的原始容貌,服务器返回的 HTML 决定了网站的原始容貌。

e23b7974e93824c066c772e0a171a0cf.png

Python3 网络爬虫快速入门实战解析

为啥说是 原始容貌 呢?因为人可以整容啊!扎心了,有木有? 那网站也可以"整容"吗?可以!请看下图:

24c6c51e2fbd33ff8c97479a9cabad9b.png

Python3 网络爬虫快速入门实战解析

我能有这么多钱吗?显然不可能。我是怎么给网站"整容"的呢?就是通过修改服务器返回的 HTML 信息。我们每个人都是"整容大师",可以修改页面信息。 我们在页面的哪个位置点击审查元素,浏览器就会为我们定位到相应的 HTML 位置,进而就可以在本地更改 HTML 信息。

再举个小例子:我们都知道,使用浏览器"记住密码"的功能,密码会变成一堆小黑点,是不可见的。可以让密码显示出来吗?可以,只需给页面"动个小手术"!以淘宝为例,在输入密码框处右键,点击检查。

ee71f70580a4705054842069f95d28fe.png

Python3 网络爬虫快速入门实战解析

可以看到,浏览器为我们自动定位到了相应的 HTML 位置。将下图中的 password 属性值改为 text 属性值( 直接在右侧代码处修改 ):

7e314f09f012879b565fed55a7097d93.png

Python3 网络爬虫快速入门实战解析

我们让浏览器记住的密码就这样显现出来了:

5f96266e570642c665e2b5723b73c1f1.png

Python3 网络爬虫快速入门实战解析

说这么多,什么意思呢? 浏览器就是作为客户端从服务器端获取信息,然后将信息解析,并展示给我们的。 我们可以在本地修改 HTML 信息,为网页"整容",但是我们修改的信息不会回传到服务器,服务器存储的 HTML 信息不会改变。刷新一下界面,页面还会回到原本的样子。 这就跟人整容一样,我们能改变一些表面的东西,但是不能改变我们的基因。

2、简单实例

网络爬虫的第一步就是根据 URL,获取网页的 HTML 信息。在 Python3 中,可以使用 urllib.requestrequests 进行网页爬取。

urllib 库是 python 内置的,无需我们额外安装,只要安装了 Python 就可以使用这个库。

requests 库是第三方库,需要我们自己安装。这个库强大好用,所以本文使用 requests 库获取网页的 HTML 信息。requests 库的 github 地址:https://github.com/requests/requests

(1)requests 安装

在 cmd 中,使用如下指令安装 requests:

1pip install requests

requests 库的基础方法如下:

bc3cf9558617a5dabc16cb760e608d7d.png

Python3 网络爬虫快速入门实战解析

官方中文教程地址:http://docs.python-requests.org/zh_CN/latest/user/quickstart.html

requests 库的开发者为我们提供了详细的中文教程,查询起来很方便。本文不会对其所有内容进行讲解,摘取其部分使用到的内容,进行实战说明。

首先,让我们看下 requests.get()方法,它用于向服务器发起 GET 请求,不了解 GET 请求没有关系。我们可以这样理解:get 的中文意思是得到、抓住,那这个 requests.get()方法就是从服务器得到、抓住数据,也就是获取数据。让我们看一个例子(以 www.gitbook.cn 为例)来加深理解:

1# -*- coding:UTF-8 -*-2import requests34if __name__ == '__main__':5    target = 'http://gitbook.cn/'6    req = requests.get(url=target)7    print(req.text)

requests.get()方法必须设置的一个参数就是 url,因为我们得告诉 GET 请求,我们的目标是谁,我们要获取谁的信息。运行程序看下结果:

c79cacc12c5eb69812eee5bf4bb771cd.png

Python3 网络爬虫快速入门实战解析

左侧是我们程序获得的结果,右侧是我们在 www.gitbook.cn 网站审查元素获得的信息。我们可以看到,我们已经顺利获得了该网页的 HTML 信息。这就是一个最简单的爬虫实例,可能你会问,我只是爬取了这个网页的 HTML 信息,有什么用呢?客官稍安勿躁,接下来进入我们的实战正文。

爬虫实战

接下来我们来一次爬虫实战,爬取中网小说网站「笔趣看」上的文字。

(1)实战背景

小说网站-笔趣看:

URL:http://www.biqukan.com/

笔趣看是一个盗版小说网站,这里有很多起点中文网的小说,该网站小说的更新速度稍滞后于起点中文网正版小说的更新速度。并且该网站只支持在线浏览,不支持小说打包下载。因此,本次实战就是从该网站爬取并保存一本名为《一念永恒》的小说,该小说是耳根正在连载中的一部玄幻小说。PS:本实例仅为交流学习,支持耳根大大,请上起点中文网订阅。

(2)小试牛刀

我们先看下《一念永恒》小说的第一章内容,URL:http://www.biqukan.com/1_1094/5403177.html

ddc0d8b8b4c8cb2110cbd792a657560d.png

Python3 网络爬虫快速入门实战解析

我们先用已经学到的知识获取 HTML 信息试一试,编写代码如下:

1# -*- coding:UTF-8 -*-2import requests34if __name__ == '__main__':5    target = 'http://www.biqukan.com/1_1094/5403177.html'6    req = requests.get(url=target)7    print(req.text)

运行代码,可以看到如下结果:

362b38e63650bbd3813d70389b8233f0.png

Python3 网络爬虫快速入门实战解析

可以看到,我们很轻松地获取了 HTML 信息。但是,很显然,很多信息是我们不想看到的,我们只想获得如右侧所示的正文内容,我们不关心 div、br 这些 html 标签。 如何把正文内容从这些众多的 html 标签中提取出来呢?这就是本次实战的主要内容。

(3)Beautiful Soup

爬虫的第一步,获取整个网页的 HTML 信息,我们已经完成。接下来就是爬虫的第二步,解析 HTML 信息,提取我们感兴趣的内容。对于本小节的实战,我们感兴趣的内容就是文章的正文。提取的方法有很多,例如使用正则表达式、Xpath、Beautiful Soup 等。对于初学者而言,最容易理解,并且使用简单的方法就是使用 Beautiful Soup 提取感兴趣内容。

Beautiful Soup 的安装方法和 requests 一样,使用如下指令安装(也是二选一):

  1. pip install beautifulsoup4
  2. easy_install beautifulsoup4

一个强大的第三方库,都会有一个详细的官方文档。我们很幸运,Beautiful Soup 也是有中文的官方文档。URL:

http://beautifulsoup.readthedocs.io/zh_CN/latest/

同理,我会根据实战需求,讲解 Beautiful Soup 库的部分使用方法,更详细的内容,请查看官方文档。

现在,我们使用已经掌握的审查元素方法,查看一下我们的目标页面,你会看到如下内容:

43af2d1e14a2634cc9d0113d7e6a1af8.png

Python3 网络爬虫快速入门实战解析

不难发现,文章的所有内容都放在了一个名为 div 的“东西下面”,这个"东西"就是 html 标签。HTML 标签是 HTML 语言中最基本的单位,HTML 标签是 HTML 最重要的组成部分。不理解,没关系,我们再举个简单的例子:

一个女人的包包里,会有很多东西,她们会根据自己的习惯将自己的东西进行分类放好。镜子和口红这些会经常用到的东西,会归放到容易拿到的外侧口袋里。那些不经常用到,需要注意安全存放的证件会放到不容易拿到的里侧口袋里。

html 标签就像一个个“口袋”,每个“口袋”都有自己的特定功能,负责存放不同的内容。显然,上述例子中的 div 标签下存放了我们关心的正文内容。这个 div 标签是这样的:

1

细心的朋友可能已经发现,除了 div 字样外,还有 id 和 class。id 和 class 就是 div 标签的属性,content 和 showtxt 是属性值,一个属性对应一个属性值。这东西有什么用?它是用来区分不同的 div 标签的,因为 div 标签可以有很多,我们怎么加以区分不同的 div 标签呢?就是通过不同的属性值。

仔细观察目标网站一番,我们会发现这样一个事实: class 属性为 showtxt 的 div 标签,独一份!这个标签里面存放的内容,是我们关心的正文部分。

知道这个信息,我们就可以使用 Beautiful Soup 提取我们想要的内容了,编写代码如下:

 1# -*- coding:UTF-8 -*- 2from bs4 import BeautifulSoup 3import requests 4if __name__ == "__main__": 5     target = 'http://www.biqukan.com/1_1094/5403177.html' 6     req = requests.get(url = target) 7     html = req.text 8     bf = BeautifulSoup(html) 9     texts = bf.find_all('div', class_ = 'showtxt') 10     print(texts)

在解析 html 之前,我们需要创建一个 Beautiful Soup 对象。BeautifulSoup 函数里的参数就是我们已经获得的 html 信息。然后我们使用 find_all 方法,获得 html 信息中所有 class 属性为 showtxt 的 div 标签。 find_all 方法的第一个参数是获取的标签名,第二个参数 class_ 是标签的属性,为什么不是 class,而带了一个下划线呢?因为 python 中 class 是关键字,为了防止冲突,这里使用 class_ 表示标签的 class 属性, class_ 后面跟着的 showtxt 就是属性值了。看下我们要匹配的标签格式:

1

这样对应的看一下,是不是就懂了?可能有人会问了,为什么不是 find_all('div', id = 'content', class_ = 'showtxt') ?这样其实也是可以的,属性是作为查询时候的约束条件,添加一个 class_='showtxt' 条件,我们就已经能够准确匹配到我们想要的标签了,所以我们就不必再添加 id 这个属性了。运行代码查看我们匹配的结果:

01f346c8e34de9ce90d92936e4f1f17a.png

Python3 网络爬虫快速入门实战解析

我们可以看到,我们已经顺利匹配到我们关心的正文内容,但是还有一些我们不想要的东西。比如 div 标签名,br 标签,以及各种空格。怎么去除这些东西呢?我们继续编写代码:

 1# -*- coding:UTF-8 -*- 2from bs4 import BeautifulSoup 3import requests 4if __name__ == "__main__": 5     target = 'http://www.biqukan.com/1_1094/5403177.html' 6     req = requests.get(url = target)  7     html = req.text 8     bf = BeautifulSoup(html) 9     texts = bf.find_all('div', class_ = 'showtxt')10     print(texts[0].text.replace('xa0'*8,''))

find_all 匹配的返回的结果是一个列表。提取匹配结果后,使用 text 属性,提取文本内容,滤除 br 标签。随后使用 replace 方法,剔除空格,替换为回车进行分段。 在 html 中是用来表示空格的。 replace('xa0'*8,'') 就是去掉下图的八个空格符号,并用回车代替:

b52475dec00c49ffab43c26f7199e078.png

Python3 网络爬虫快速入门实战解析

程序运行结果如下:

eb17c96caf02545a4deb38f0e218b5c8.png

Python3 网络爬虫快速入门实战解析

可以看到,我们很自然的匹配到了所有正文内容,并进行了分段。我们已经顺利获得了一个章节的内容,要想下载正本小说,我们就要获取每个章节的链接。我们先分析下小说目录:URL:http://www.biqukan.com/1_1094/

51fac31334e01199df1af0b8821bf18d.png

Python3 网络爬虫快速入门实战解析

通过审查元素,我们发现可以发现,这些章节都存放在了 class 属性为 listmain 的 div 标签下,选取部分 html 代码如下:

 1
2 3《一念永恒》最新章节列表 4第 1027 章 第十道门 5第 1026 章 绝伦道法! 6第 1025 章 长生灯! 7第 1024 章 一目晶渊 8第 1023 章 通天道门 9第 1022 章 四大凶兽!10第 1021 章 鳄首!11第 1020 章 一触即发!12第 1019 章 魁祖的气息!13第 1018 章 绝望的魁皇城14第 1017 章 我还是恨你!15第 1016 章 从来没有世界之门!16《一念永恒》正文卷 外传 1 柯父。17外传 2 楚玉嫣。 外传 3 鹦鹉与皮冻。18第一章 他叫白小纯 第二章 火灶房19第三章 六句真言 第四章 炼灵2021

在分析之前,让我们先介绍一个概念:父节点、子节点、孙节点。

限定了
标签的开始和结束的位置,他们是成对出现的,有开始位置,就有结束位置。我们可以看到,在
标签包含 标签,那这个 标签就是
标签的子节点, 标签又包含 标签和 标签,那么 标签和 标签就是
标签的孙节点。有点绕?那你记住这句话: 谁包含谁,谁就是谁儿子!

他们之间的关系都是相对的。比如对于

标签,它的子节点是 标签,它的父节点是 标签。这跟我们人是一样的,上有老下有小。

看到这里可能有人会问,这有好多

标签和 标签啊!不同的 标签,它们是什么关系啊?显然,兄弟姐妹喽!我们称它们为兄弟结点。

好了,概念明确清楚,接下来,让我们分析一下问题。我们看到每个章节的名字存放在了 标签里面。 标签还有一个 href 属性。这里就不得不提一下 标签的定义了, 标签定义了一个超链接,用于从一张页面链接到另一张页面。 标签最重要的属性是 href 属性,它指示链接的目标。

我们将之前获得的第一章节的 URL 和 标签对比看一下:

1http://www.biqukan.com/1_1094/5403177.html

不难发现, 标签中 href 属性存放的属性值 /1_1094/5403177.html 是章节 URL http://www.biqukan.com/1_1094/5403177.html 的后半部分。其他章节也是如此!那这样,我们就可以根据 标签的 href 属性值获得每个章节的链接和名称了。

总结一下:小说每章的链接放在了 class 属性为 listmain 的

标签下的 标签中。链接具体位置放在 html->body->div->dl->dd->a 的 href 属性中。先匹配 class 属性为 listmain 的
标签,再匹配 标签。编写代码如下:
 1# -*- coding:UTF-8 -*- 2from bs4 import BeautifulSoup 3import requests 4if __name__ == "__main__": 5     target = 'http://www.biqukan.com/1_1094/' 6     req = requests.get(url = target) 7     html = req.text 8     div_bf = BeautifulSoup(html) 9     div = div_bf.find_all('div', class_ = 'listmain')10     print(div[0])

还是使用 find_all 方法,运行结果如下:

8f4239a03f2e8f85be5949932024023b.png

Python3 网络爬虫快速入门实战解析

很顺利,接下来再匹配每一个 标签,并提取章节名和章节文章。如果我们使用 Beautiful Soup 匹配到了下面这个 标签,如何提取它的 href 属性和 标签里存放的章节名呢?

1第一章 他叫白小纯

方法很简单,对 Beautiful Soup 返回的匹配结果 a,使用 a.get('href')方法就能获取 href 的属性值,使用 a.string 就能获取章节名,编写代码如下:

 1# -*- coding:UTF-8 -*- 2from bs4 import BeautifulSoup 3import requests 4if __name__ == "__main__": 5     server = 'http://www.biqukan.com/' 6     target = 'http://www.biqukan.com/1_1094/' 7     req = requests.get(url = target) html = req.text 8     div_bf = BeautifulSoup(html) 9     div = div_bf.find_all('div', class_ = 'listmain')10     a_bf = BeautifulSoup(str(div[0]))11     a = a_bf.find_all('a')12     for each in a:13          print(each.string, server + each.get('href'))

因为 find_all 返回的是一个列表,里边存放了很多的 标签,所以使用 for 循环遍历每个 标签并打印出来,运行结果如下:

0c38aa2f87bfb9c4d06b3cfa8a0aeb8f.png

Python3 网络爬虫快速入门实战解析

最上面匹配的一千多章的内容是最新更新的 12 章节的链接。这 12 章内容会和下面的重复,所以我们要滤除,除此之外,还有那 3 个外传,我们也不想要。这些都简单地剔除就好。

(3)整合代码

每个章节的链接、章节名、章节内容都有了。接下来就是整合代码,将获得内容写入文本文件存储就好了。编写代码如下:

 1# -*- coding:UTF-8 -*- 2from bs4 import BeautifulSoup 3import requests, sys 4 5class downloader(object): 6    def __init__(self): 7        self.server = 'http://www.biqukan.com/' 8        self.target = 'http://www.biqukan.com/1_1094/' 9        self.names = []            #存放章节名10        self.urls = []            #存放章节链接11        self.nums = 0            #章节数1213    def get_download_url(self):14        req = requests.get(url = self.target)15        html = req.text16        div_bf = BeautifulSoup(html)17        div = div_bf.find_all('div', class_ = 'listmain')18        a_bf = BeautifulSoup(str(div[0]))19        a = a_bf.find_all('a')20        self.nums = len(a[15:])                                #剔除不必要的章节,并统计章节数21        for each in a[15:]:22            self.names.append(each.string)23            self.urls.append(self.server + each.get('href'))2425    """26    函数说明:获取章节内容27    Parameters:28        target - 下载连接(string)29    Returns:30        texts - 章节内容(string)31    """32    def get_contents(self, target):33        req = requests.get(url = target)34        html = req.text35        bf = BeautifulSoup(html)36        texts = bf.find_all('div', class_ = 'showtxt')37        texts = texts[0].text.replace('xa0'*8,'')38        return texts3940    """41    函数说明:将爬取的文章内容写入文件42    Parameters:43        name - 章节名称(string)44        path - 当前路径下,小说保存名称(string)45        text - 章节内容(string)46    Returns:47        无48    """49    def writer(self, name, path, text):50        write_flag = True51        with open(path, 'a', encoding='utf-8') as f:52            f.write(name + '')53            f.writelines(text)54            f.write('')5556if __name__ == "__main__":57    dl = downloader()58    dl.get_download_url()59    print('《一年永恒》开始下载:')60    for i in range(dl.nums):61        dl.writer(dl.names[i], '一念永恒.txt', dl.get_contents(dl.urls[i]))62        sys.stdout.write("  已下载:%.3f%%" %  float(i/dl.nums*100) + '')63        sys.stdout.flush()64    print('《一年永恒》下载完成')

很简单的程序,单进程跑,没有开进程池。下载速度略慢,喝杯茶休息休息吧。代码运行效果如下图所示:

e3348c84b029d964b56142a76047da72.gif

Python3 网络爬虫快速入门实战解析

以上就是一次爬虫实战。

来和小伙伴们一起向上生长呀!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值