Python爬虫教程:如何高效抓取多级页面数据(以电影天堂为例)
前面讲解的爬虫案例是单级页面数据的抓取。然而,有些时候,仅抓取一个单级页面是无法完成数据提取的。所以,本节将讲解怎样使用爬虫来抓取多级页面的数据。

在爬虫进行的过程里,经常会遇到多级页面抓取的情况。接下来以抓取二级页面作为例子,对每级页面的作用进行阐释:
一级页面通过标签与二级页面相链接,只有在二级页面才能够提取到所需数据。接下来以电影天堂(点击访问)2020 新片精品为例进行讲解,要把每部影片的名称以及下载链接抓取下来。首先点击“更多”,从而进入一级页面,如下图所示:
图1:Python爬虫多级页面抓取
通过简单分析能够得知,寻找 url 规律时,一级页面和二级页面均为静态页面。接着分析 url 规律,点击第 1 页、第 2 页等,其规律如下:
https://www.dytt8.net/html/gndy/dyzz/list_23_1.html 位于第 1 页 https://www.dytt8.net/html/gndy/dyzz/list_23_2.html 位于第 2 页。 第 n 页的链接为 https://www.dytt8.net/html/gndy/dyzz/list_23_n.html 。
通过元素审查能够确定正则表达式,一级页面的元素结构情况如下:
图2:页面元素分析
其正则表达式如下:
点击二级页面后进入详情页,利用开发者工具去分析所想要数据的网页元素,也就是电影名称以及下载链接,其正则表达式为:
.*?(.*?)
.*?爬虫增量抓取是一种效率低的程序,会大量消耗计算机资源。聚焦爬虫程序需每天对特定网站进行数据抓取,若每次都抓取已抓取过的数据,就会浪费时间和资源。增量爬虫是指通过监测网站更新情况,只抓取最新数据的方式,能大大降低资源消耗。
对于本节案例而言,电影天堂网站每天都有内容更新。所以,编写一个增量抓取的爬虫程序是很合适的。
那么怎样判断爬虫程序是否已抓取过二级页面的 url 呢?当您首次运行爬虫程序时,爬虫会把所有的 url 抓取下来,接着把这些 url 放入数据库里。为提升数据库的查询效率,您可以给每一个 url 生成专门的“指纹”。网站更新后,再次运行爬虫程序,此时程序只会抓取数据库中不存在的指纹。
2. 这里要将 url 指纹单独存放在一张表中,具体如下。
创建一个名为 movieskydb 的数据库,其字符集为 utf8。 use movieskydb; create table request_finger( finger char(60) )charset=utf8; create table movieinfo( moviename varchar(300), downloadaddr varchar(600) )charset=utf8;您可以使用 Python 内置的 md5 模块来生成加密“指纹”,具体如下:通过该模块生成 url 的指纹。
#导入模块 from hashlib import md5 #待加密的url 该链接为 https://www.dytt8.net/html/gndy/dyzz/20210226/61131.html 。 # 生成MD5对象 secret = md5() # 加密url secret.update(url.encode()) # 提取十六进制的加密串 finger = secret.hexdigest() print(finger)输出结果:
请提供具体需要改写的句子呀,没有看到横线下的内容呢。3) 程序完整代码
# -*- coding: utf-8 -*- from urllib import request import re import time import random import pymysql from hashlib import md5 from ua_info import ua_list import sys class MovieSkySpider(object): def __init__(self): self.url 等于 'https://www.dytt8.net/html/gndy/dyzz/list_23_' 加上一个占位符,这个占位符可以被替换为具体的数字,从而形成不同的页面链接。 self.db = pymysql.connect( 本地主机、根用户、123456、movieskydb charset='utf8' ) self 拥有一个游标,这个游标是 self.db 的游标。 # 1.请求函数 def get_html(self, url): headers 包含了一个键值对,键为 'User-Agent',值为从 ua_list 中随机选择的一个元素。 req 是一个 request.Request 对象,它的 url 属性被设置为指定的 url,它的 headers 属性被设置为指定的 headers。 res = request.urlopen(req) # 本网站使用gb2312的编码格式 res 读取的内容通过 decode 方法以 'gb2312' 编码进行解码,并且忽略解码过程中的错误,得到的结果为 html 。 return html # 2.正则解析函数 定义一个名为 re_func 的函数,该函数接收两个参数,分别是 re_bds 和 html。 re_bds 被用于创建一个正则表达式模式,该模式由 re.compile 函数进行编译,编译后的模式被赋值给变量 pattern ,并且在编译过程中使用了 re.S 标志。 pattern 在 html 中进行查找,查找到的结果存储在 r_list 中。 return r_list # 3.提取数据函数 def parse_html(self,one_url): # 调用请求函数,获取一级页面 self 获取了 one_url 的 HTML 内容并赋值给 one_html 。 re_bds = '.*?
' # 获取二级页面链接 链接列表为:['/html//html/gndy/dyzz/20210226/61131.html', '/html/xxx', '', ''] self.re_func(re_bds,one_html) 被赋值给了 link_list 。 for link in link_list: # 判断是否需要爬取此链接 # 1.获取指纹 # 拼接二级页面url two_url 等于 'https://www.dytt8.net' 加上 link 。 s = md5() #加密url,需要是字节串 s.update(two_url.encode()) # 生成指纹,获取十六进制加密字符串, finger = s.hexdigest() # 2.通过函数判断指纹在数据库中是否存在 if self.is_hold_on(finger): # 抓取二级页面数据 self.save_html(two_url) 等待一段时间,这段时间的长度是在 1 到 2 之间随机生成的整数。 # 抓取后,把想用的url专属指纹存入数据库 “insert into request_finger values 后面跟一个占位符 %s” self 的游标执行插入操作 ins,传入参数 [finger] 。 self.db.commit() else: sys.exit('更新完成') # 4.判断链接是否已经抓取过 def is_hold_on(self,finger): # 查询数据库 sql 为 'select finger from request_finger where finger 等于 %s' execute()函数的返回值是受影响的行数,这个行数要么是 0,要么是非 0。 self.cursor 执行了 sql 语句,并且传入了 finger 参数,执行的结果赋值给了 r 。 # 如果为0表示没有抓取过 if not r: return True # 5.解析二级页面,获取数据(名称与下载链接) def save_html(self,two_url): self 获取了 two_url 的 HTML 内容并赋值给 two_html 。 re_bds = '.*?(.*?)
\以下是改写后的句子:该样式的背景颜色为特定的某种情况。(这里的“特定的某种情况”需根据具体文档中该样式的背景颜色实际情况来确定)' film_list 包含多个元素,每个元素是一个包含两个元素的元组,第一个元素为 'name',第二个元素为 'downloadlink',这些元组组成了一个列表,如 ('name','downloadlink')、()、() 等。 self.re_func(re_bds, two_html) 被赋值给了 film_list 。 print(film_list) # 插入数据库 sql 等于 '向 movieinfo 表中插入值,值为(%s,%s)' #L = list(film_list[0]) self 的游标执行了多个 SQL 语句,这些 SQL 语句是通过 film_list 提供的参数来执行的。 self.db.commit() #主函数 def run(self): # 二级页面后四页的正则表达式略有不同,需要重新分析 for i in range(1,4): url = self.url.format(i) self.parse_html(url) 如果 __name__ 的值为 '__main__' 。 spider = MovieSkySpider() spider.run() 若要查询数据库存储数据,执行以下命令即可:
mysql 执行从 movieinfo 表中查询所有数据的操作并以表格形式展示。输出如下,如下图所示:
图3:MySQL数据库存储数据
在提取二级页面的数据时,需要留意该页面的类型。此网站在二级页面运用了两种类型的网页结构,另一种页面结构的正则表达式情况如下:
.*?(.*?)
若要抓取此类页面的数据,需要更换二级页面正则表达式。 你可能想看: