Skip to content

Latest commit

 

History

History
258 lines (185 loc) · 10.3 KB

03-第三周-我们的第一个爬虫.md

File metadata and controls

258 lines (185 loc) · 10.3 KB

我们的第一个爬虫

本篇文章涉及到的内容如下:

  • Python第三方库的安装方法
  • 学会使用Requests库的使用方法
  • BeautifulSoup库的使用方法
  • Requests库和BeautifulSoup库的组合使用。

Python的第三方库

Python之所以如此火热和流行,有很大的原因是因为它有很多很强大的第三方库。这样“程序猿”们就不用太了解底层的实现,用最少的代码写出最多的功能。就像我们之前说的购买车票一样,需要:

  • 打印车票的纸和墨
  • 一台可以打印的机器
  • 查询座位等操作。

如果没有使用第三方库的话,恐怕我们买一张车票要一步一步的把上面需要的东西都实现一遍。这样购买一张车票是不是要很久啊。如今有了自动售票机这个“第三方库”,我们只需几十秒就可以拿到车票。这种拿来即用的在Python中就是第三方库。

  1. 如何安装第三方库呢

    • 纯原生的安装方法

      pip install 第三方库的名称
    • 在anaconda环境中安装

      conda install 第三方库的名称
    • 当然还可以通过源码安装

      我们将源码下载到本地,解压后会看到一个文件夹目录,里面有一个setp.py的文件,然后我们在该文件的同级目录下,执行如下代码即可:

      python setp.py install

    以上这些方法都是在你的电脑上只有一个python环境的前提下。如果同时存在Python2 和python3的情况下,恐怕要小心一下了。看看你默认的环境是哪个。具体大家遇到问题可以在群里面@我一下。什么?! 还没加群,那快快扫描文章下面的二维码加入进来。会有很多福利的。

  2. 安装好后如何使用

    其实使用Python的第三方库很简单,只需要在你的代码开头将它导入进来就可以了。

    import time # 这个库是Python自带的。可以直接这样引入
    from BS4 import BeautifulSoup # 从我们安装的第三方库中引入进来

Requests库

Requests库的作用就是请求网站获取网页数据的,让我们从简单的实例开始,讲解Requests的使用方法。

我们这里的示例网站是,爱站的ICP备案查询https://icp.aizhan.com。我们查询的网站是www.csdn.net

这里的目标url为:https://icp.aizhan.com/www.csdn.net/

我们新建一个main.py的文件。将如下代码写在里面。

我建议大家在一个固定的地方建一个文件夹,用来保存我们专栏的所有的代码,等专栏结束后看看你的成就,也许会很吃惊的哦。

import requests
# 这里想查的CSDN的备案信息
res = requests.get('https://icp.aizhan.com/www.csdn.net/') 
print(res)
print(res.text)

然后在控制台(cmd)中输入:

python main.py

得到如下画面,表示你已经成功的爬取了这个网站的代码信息,恭喜你,你已经成功的入了爬虫的坑。

1566045583808

  1. 我们看到有一个**<Response [200]>**,代表的意思请求网站成功,若为404,400则表示请求失败,具体的原因有很多。比如:网站地址输错,当然也有可能触发了反爬机制。
  2. 上面的一堆HTML代码就是我们爬取的内容,我们可以通过在浏览器中F12来比较一下我们获取的内容和目标网站的代码是否一致。

大部分时候,我们都要在爬虫中添加请求头,让服务器误以为我们是通过浏览器访问的,这样可以减少触发反爬机制的几率。

那么如何伪装成浏览器呢?我只需要在get方法里面添加一个headers的参数即可。

如何获取header的内容呢?

我们在浏览器中按F12打开开发者工具。刷新页面,然后找到User-Agent,这就是我们的请求头。

1566046413728

然后修改代码:

import requests

headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko)\
         Chrome/76.0.3809.100 Safari/537.36'
}
# 这里想查的CSDN的备案信息
res = requests.get('https://icp.aizhan.com/www.csdn.net/', headers = headers) 
print(res)
print(res.text)

这里的headers是一个字典。这里的value会很长,我们可以在合适的地方添加一个\来让它换行。

Requests库不仅有get方法,还有post方法,通常是用来登录的,我们在后面的实战中会用到,这里暂时就不多说了。

我们用这个库来访问网站,有时会出现问题,常见的如下:

  • ConnectionError:通常是网络问题(如DNS查询失败,拒绝连接等)
  • HTTPError:原因为请求返回了一个不成功的状态码,比如404等。
  • Timeout异常:请求超时
  • TooManyRedirects异常,原因为超过了设定的最大重定向次数。

我们在实际代码的中通常是需要做异常处理的

import requests

headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko)\
         Chrome/76.0.3809.100 Safari/537.36'
}
# 这里想查的CSDN的备案信息
res = requests.get('https://icp.aizhan.com/www.csdn.net/', headers = headers) 
# 异常处理
try:
    print(res.text)
except ConnectionError:
    print("连接失败")

当出现连接失败的时候,就会在控制台打印一个信息告诉开发者连接失败了。

BeautifulSoup库

我们在上面通过requests库获取到了页面代码,但是如何能准确的提取出我们需要的信息呢?

我们在之前的代码中引入我们的BeautifulSoup库。

import requests
from bs4 import BeautifulSoup

headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko)\
         Chrome/76.0.3809.100 Safari/537.36'
}
# 这里想查的CSDN的备案信息
res = requests.get('https://icp.aizhan.com/www.csdn.net/', headers = headers) 
# 异常处理
try:
    # 对返回结果尽心解析
    soup = BeautifulSoup(res.text, 'html.parser')
    print(soup.prettify())
except ConnectionError:
    print("连接失败")

同样通过在命令行中运行

python main.py

会得到页面代码,这时的代码和之前其实是一样的,只不过BS4(我们后面都将BeautifulSoup库简称为BS4)对它进行了标准的缩进格式化。

BS4除了支持Python标准库的HTML解析器外,还支持一些第三方的解析器。如下:

解析器 使用方法 有点 缺点
Python标准库 BeautifulSoup(res.text, 'html.parser') 内置库执行速度适中,文档容错能力强 旧版本(3.2.2)前的容错性差
lxml HTML解析器 BeautifulSoup(res.text, 'lxml') 速度快,文档容错能力强 需要安装C语言库
lxml XML解析器 BeautifulSoup(res.text, 'lxml') 或者BeautifulSoup(res.text, ['lxml', 'xml']) 速度快,唯一支持XML的解析器 同上
html5lib BeautifulSoup(res.text, 'html5lib') 最好的容错性,以浏览器的方式解析文档生成HTML5格式的文档 速度慢,不依赖外部扩展

BS4官方推荐使用lxml作为解析器,因为效率高。

解析得到的Soup文档可以使用**find(), find_all()以及selector()**方法定位到需要的元素。

find和find_all的用法类似

soup.find_all('div', 'item')
soup.find_all('div', class = 'item')
soup.find_all('div', attrs = {'class':'item'})

以上这三行代码的功能是一样的,都是通过class来获取div元素。

find_all和find的返回类型不一样,前者返回所有符合条件的元素列表,而后知只返回一个元素。

soup.selector(#icp-table > table > tbody > tr:nth-child(1) > td:nth-child(2))

这个是通过标签的层级关系来获取指定的内容的。可以在谷歌浏览器中在指定元素上面右键,然后有一个copy里面可以选择selector就可以得到括号里面的内容了。

tr:nth-child(1) 需要修改的,在Python中需要改成tr:nth-of-type(1)

接下来演示一下如何获取到主办单位名称备案号

import requests
from bs4 import BeautifulSoup

headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko)\
         Chrome/76.0.3809.100 Safari/537.36'
}
# 这里想查的CSDN的备案信息
res = requests.get('https://icp.aizhan.com/www.csdn.net/', headers = headers) 
# 异常处理
try:
    # 对返回结果尽心解析
    soup = BeautifulSoup(res.text, 'html.parser')
    # 通过find_all()获取主办单位名称
    div = soup.find('div', attrs = {'id':'icp-table'})
    td_list = div.find_all('td')
    name_info = td_list[0].text + ":" + td_list[1].text
    print(name_info) 
    # 通过selector获取备案号
    icp_no = soup.select('#icp-table > table > tr:nth-of-type(3) > td:nth-of-type(2) > span')[0].get_text()
    print(icp_no) 
except ConnectionError:
    print("连接失败")

运行后得到:

1566049929368

这里有几点需要注意一下

  1. 我们在使用selector的时候,用的方法是select()

  2. 我们在复制了selector内容后需要修改,不能直接使用

    我们复制的内容:

    #icp-table > table > tbody > tr:nth-child(3) > td:nth-child(2) > span

    实际写入代码的内容:

    #icp-table > table > tr:nth-of-type(3) > td:nth-of-type(2) > span

  3. 我们要获取的是文本,所以需要在获取对象后,在调用一些方法类获信息,如:get_text()等

好了,今天的内容就是这些。大家下去把其他的信息也取一下,如果有问题欢迎大家在群里积极讨论。