将多条爬虫数据存储到MongoDB里面 爬虫爬取多页数据_爬虫


由本人进行改动与整理,并且增加部分注释。

上节我们是用各个方法获取一个页面中指定的一个内容,这次我们实现多个页面,同一组数据的获取。

1.BeautifulSoup().find_all()方法(select()的升级版)

我们是爬取酷狗音乐TOP500 的‘音乐名’,‘歌手’,‘歌名’,‘播放时间’这几个数据网址如下:

打开后只能看到前 22 名的数据,我们可以看到,在网址中有一个 1-8888 这个参数,打开上述网址后我们只能看到前 22 首歌,想继续查看后面的歌曲就得翻页,就像“淘宝”那样查看下一页商品需要翻页,这里也是一样的道理,把 1-8888 改成 2-8888 ,就会看到下一页的 22 首歌。

本次使用的方法,就是把上一篇的 select 方法换成 find_all 方法

find_all(标签名,class_=类名)

第一个参数是标签名,我们来看排名的标签如下:

将多条爬虫数据存储到MongoDB里面 爬虫爬取多页数据_将多条爬虫数据存储到MongoDB里面_02

可以看到它的标签名为 span,class 属性名为 pc_tempnum,所以find_all()中填入’span’,class_=‘pc_temp_num’,同理,歌手,歌名,播放时间的如下:

# 歌手 + 歌名
names = html.find_all('a',class_='pc_temp_songname')
# 播放时间
times = html.find_all('span',class_='pc_temp_time')

具体代码如下:

import requests
import time
from bs4 import BeautifulSoup
import lxml


def get_html(url):
    '''
    获得 HTML,并且构造一个请求头,有了请求头之后,服务器就会默认程序是通过浏览器访问的
    请求头中的信息其实在网页按F12后,点network,然后f5刷新一下,看主要文件在右边显示的信息里
    一般是有index字样的文件,信息在user-agent中
    '''
    headers = {
        'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/53\
        7.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36'
    }
    response = requests.get(url, headers=headers)
    if response.status_code == 200:
        return response.text
        #这是判断网页返回的状态码,200代表连接成功,大家常见的应该是404和503
        #状态码一般在爬虫程序出错时,作为检测工具,用断点然后打印出来,判断连接网站时出现的错误
        #具体的各个状态码代表什么意思,出现问题后,自行百度即可
    else:
        return


def get_infos(html):
    '''
    提取数据
    '''
    html = BeautifulSoup(html,'lxml')
    # 排名
    ranks = html.find_all('span',class_='pc_temp_num')
    # 歌手 + 歌名
    names = html.find_all('a',class_='pc_temp_songname')
    # 播放时间
    times = html.find_all('span',class_='pc_temp_time')

    # 打印信息
    for r,n,t in zip(ranks,names,times):
        r = r.get_text().replace('\n','').replace('\t','').replace('\r','')
        n = n.get_text()
        t = t.get_text().replace('\n','').replace('\t','').replace('\r','')
        data = {
            '排名': r,
            '歌名-歌手': n,
            '播放时间': t
        }
        print(data)


def main():
    '''
    主接口
    '''
    urls = ['https://www.kugou.com/yy/rank/home/{}-8888.html?from=rank'
                .format(str(i)) for i in range(1, 24)]
    for url in urls:
        html = get_html(url)
        get_infos(html)
        time.sleep(1)
        #每过一秒,再次执行下一个网页,避免给服务器造成压力,也避免自己的计算机能力不够,运算过快死机


if __name__ == '__main__':
    main()

用了 zip 函数,意思是把对应的排名,歌名歌手,播放时间打包,可以这样理解 zip 函数的结果是一个列表 [(排名,歌手歌名,播放时间),(排名,歌手歌名,播放时间)… …],而每一次循环的 r,n,t 一次对应元组中的元素。
我们提取到的是这个数据所在的标签信息,并不是实际数据,所以需要使用 get_text() 获得实际数据。
.replace(’\n’,’’).replace(’\t’,’’).replace(’\r’,’’)是为了去掉实际数据中多余的字符串,最后把数据打包成字典打印。
输出结果为:
{‘排名’: ‘1’, ‘歌名-歌手’: ‘杨胖雨 - 这就是爱吗’, ‘播放时间’: ‘4:04’}
{‘排名’: ‘2’, ‘歌名-歌手’: ‘魏新雨 - 百花香’, ‘播放时间’: ‘2:47’}
{‘排名’: ‘3’, ‘歌名-歌手’: ‘棉子 - 勇气’, ‘播放时间’: ‘4:01’}
{‘排名’: ‘4’, ‘歌名-歌手’: ‘阿悠悠 - 你若三冬’, ‘播放时间’: ‘4:18’}
……

2.etree.HTML().xpath()方法

爬取中国大学2019的排名信息,爬取‘排名’,‘学校名’,‘省份’,‘总分’,这四个字段信息。

右键-检查,查看元素如下图:

将多条爬虫数据存储到MongoDB里面 爬虫爬取多页数据_数据_03

可以看到,我们所需要的数据是画红线部分的数据,我们把它折叠起来,tr 标签左边有个小箭头,点击折叠,如图:

将多条爬虫数据存储到MongoDB里面 爬虫爬取多页数据_html_04

折叠后我们可以看到,高亮条对应的部分,意思是每一条‘排名’‘学校名’‘省份’‘总分’都对应一个 … 标签。
我们拉到网页最底部,可以看到有 549 个学校,就是说这样的标签有 549 条,我们需要先提取它们,再从每一条标签提取信息。提取所有的学校信息的标签,使用 xpath 方法选择标签在 html 源码里的路径,// 是选择此 html 源码里所有 tr 标签并且 class 属性为 alt 的标签。

import requests
import time
from lxml import etree


def get_html(url):
    '''
    获得 HTML
    '''
    headers = {
        'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/53\
        7.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36'
    }
    response = requests.get(url, headers=headers)
    if response.status_code == 200:
        response.encoding = 'utf-8'#响应的结果的 html 源码的编码格式设置成 utf-8,也可以设成上一节的自动识别网页编码
        return response.text
    else:
        return


def get_infos(html):
    '''
    提取数据
    '''
    html = etree.HTML(html)
    # 提取所有的大学标签信息
    ls = html.xpath('//tr[@class="alt"]')
    for info in ls:
        # 排名
        rank = info.xpath('./td[1]/text()')[0]
        # 学校名
        name = info.xpath('./td[2]/div/text()')[0]
        # 省份
        province = info.xpath('./td[3]/text()')[0]
        # 总分
        score = info.xpath('./td[4]/text()')[0]
        data = {
            '排名' : rank,
            '校名' : name,
            '省份' : province,
            '总分' : score,
        }
        print(data)


def main():
    '''
    主接口
    '''
    url = 'http://www.zuihaodaxue.com/zuihaodaxuepaiming2019.html'
    html = get_html(url)
    get_infos(html)
    time.sleep(1)


if __name__ == '__main__':
    main()

输出结果为:
{‘排名’: ‘1’, ‘校名’: ‘清华大学’, ‘省份’: ‘北京’, ‘总分’: ‘94.6’}
{‘排名’: ‘2’, ‘校名’: ‘北京大学’, ‘省份’: ‘北京’, ‘总分’: ‘76.5’}
{‘排名’: ‘3’, ‘校名’: ‘浙江大学’, ‘省份’: ‘浙江’, ‘总分’: ‘72.9’}
{‘排名’: ‘4’, ‘校名’: ‘上海交通大学’, ‘省份’: ‘上海’, ‘总分’: ‘72.1’}
……

3.正则表达式匹配网页内容

我们这次的目标是一个小说网站的的小说章节的标题的爬取,我们使用正则来提取我最爱的玄幻小说《斗破苍穹》的章节标题。

将多条爬虫数据存储到MongoDB里面 爬虫爬取多页数据_python_05

网页的整体结构很简单,所以爬取起来,也比较容易:

将多条爬虫数据存储到MongoDB里面 爬虫爬取多页数据_将多条爬虫数据存储到MongoDB里面_06

正则表达式匹配的方式就是在网页源码中,抓取需要的字符串,可能大家想,匹配第XXX章并且截止到之前就好了,但是我们这次使用匹配前面的链接就好了。而获取到的网页源码,只要不进行编译,其实和txt文本一样,乱糟糟的没有规律和美感可言,所以我们选择匹配标签里的网页属性就好了,正好它的数字也是随着章数的变化而变化。
我们使用 findall() 方法
pat:正则表达式,html:网页源码,指的是 response.text,re.S:是一种匹配的模式,是指允许换行匹配,因为在构造正则时,网页源码可能换行了就需要它,它返回的是一个列表,包含了在此 html 源码中匹配的符合的结果。

import requests
import re
from fake_useragent import UserAgent


def get_html(url):
    '''
    请求 html
    :return:
    '''
    headers = {
        'User-Agent' : UserAgent().random
    }
    response = requests.get(url,headers=headers)
    if response.status_code == 200:
        response.encoding = 'utf-8'
        return response.text
    else:
        return


def get_info(html):
    '''
    提取文章标题
    :param html:
    :return:
    '''
    pat = '<dd> <a style="" href="/book/390/\d+.html">(.*?)</a></dd>'
    titles = re.findall(pat,html,re.S)
    for title in titles:
        print(title.replace("VIP章节目录 ",""))#中间部分章节前面带有“VIP章节目录”字样,所以处理一下


if __name__ == '__main__':
    '''
    主接口
    '''
    url = 'https://www.jx.la/book/390/'
    html = get_html(url)
    if html == None:
        print('请求失败!')
    get_info(html)

输出结果为:
第一章 陨落的天才
第二章 斗气大陆
第三章 客人
第四章 云岚宗
……
总结
通过以上三种方法获取网站中一组数据,我们进行总结这三种方法,分析它们的长处。
首先是处理方法上,第三种最简单,只是对于网页中的字符串进行正则匹配,不需要进行网页渲染,适合获取网站结构简单,并且标签内容相似的网站。
第二种寻找XPath的方法,则适合匹配内容组多,但是网页结构不复杂的网页。
第一种相较于第二种,更适合网页结构复杂,同种标签太多并且需要获取多组数据的网页。
所以如果只是针对同一个网页进行数据获取,很难体现它们的不同和优点来,故三个代码片段我就直接搬运了过来,并且修正了部分代码,增加一些注释,如果觉得代码太长难以一下子理解,可以去代码原作者那里去看分步解释。