python-对豆瓣的top250的爬取(利用正则表达式)

之前写了一个猫眼的爬虫的代码。是利用了request()和beautifulsoup()。但是之前的方法是利用了selector的搜索方法。最近学习了一点正则表达式,用正则表达式对豆瓣的top250进行了尝试。

豆瓣一直都是我比较喜欢的一个app,我也很喜欢看电影,你如果喜欢,在我的博客里有我的豆瓣链接,我们可以互粉一下聊聊电影hhhhhh,看得不多,但坚持再看并且写影评。

这次爬取下来top250的数据也非常高兴。

正则表达式的定义

正则表达式,又称规则表达式**。**(英语:Regular Expression,在代码中常简写为regex、regexp或RE),计算机科学的一个概念。正则表达式通常被用来检索、替换那些符合某个模式(规则)的文本。

import re

python如果要使用正则表达式,首先需要引用re库

re库是一个python中有关于正则表达式的第三方库。因为我们在匹配过程中,也需要一些函数来剔除我们不需要的冗余字符。

正则表达式常用操作符(1)

操作符 说明 实例
. 表示任何单个字符 比如在非贪婪匹配中(.*?)
[ ] 字符集,对单个字符给出取值范围 [abc]表示a/b/c,[a-z]表示a到z的单个字符
[^ ] 非字符集,对单个字符给出排除范围 [^abc]表示非a非b非c的单个字符
* 前一个字符0次或无限次扩展 abc*表示为ab/abc/abccc
+ 前一个字符1次或无限次扩展 abc+表示abc/abcc/abccc
? 前一个字符0次或1次扩展 abc?表示ab/abc
| 左右表达式的任意一个 abc | def表示 abc、def

正则表达式的常用操作符(2)

操作符 说明 实例
{m} 扩展前一个字符m次 ab{2}c表示abbc
{m,n} 扩展前一个字符m至n次(含n) ab{1,2}c表示abc、abbc
^ 匹配字符串开头 ^abc表示abc且在一个字符串的开头
$ 匹配字符串结尾 abc$表示abc且在一个字符串的结尾
( ) 分组标记,内部只能使用 | 操作符 (abc)表示abc,(abc | def)表示abc、def
\d 数字,等价于[0-9]
\w 单词字符,等价于[A-Za-z0-9_]
常用标记 说明
re.I re.IGNORECASE 忽略正则表达式中的大小写,[A-Z]能够匹配小写字符
re.M re.MULTILINE 正则表达式中的^操作符能够将给定字符串的每行当作匹配开始
re.S re.DOTALL 正则表达式中的.操作符能够匹配所有字符,默认匹配除了换行以外的所有字符

以上这些常用的操作符对于爬虫来说是足够的了,我们还需要的是怎么去使用去让其匹配。

正则表达式的练习我用的是anaconda中的jupyter进行练习。

几种常见的匹配方式

首先引用这个库,常规操作

import re
最常规匹配
content='Hello 123 4567 World_This is a Regex Demo'
print(len(content))
result=re.match('^Hello\s\d\d\d\s\d{4}\s\w{10}.*Demo$',content)
print(result)
print(result.group())#group()表示取全部匹配的字符串或者指定的组,返回结果是一个字符串
print(result.span())#span()表示返回一个元组包含匹配 (开始,结束) 的位置

输出结果

41
<re.Match object; span=(0, 41), match='Hello 123 4567 World_This is a Regex Demo'>
Hello 123 4567 World_This is a Regex Demo
(0, 41)

#这是最常规的匹配,将每一个字符都用操作符
#\s 是一个匹配空格 \d 匹配数字 \d{4} 匹配一串数字
#.*Demo$ 点用于匹配之前的 *作为前一个字符的匹配与'点'一起 最后用$作为一个匹配字符串的结尾
泛匹配
content = 'Hello 123 4567 World_This is a Regex Demo'
result = re.match('^Hello.*Demo$',content)
print(result)
print(result.group())

输出结果

<re.Match object; span=(0, 41), match='Hello 123 4567 World_This is a Regex Demo'>
Hello 123 4567 World_This is a Regex Demo

#泛匹配就比较省略,有前面和后面的字符就行,中间的不需要也可以
匹配目标
content = 'Hello 1234567 World_This is a Regex Demo'
result = re.match('^Hello\s(\d+)\sWorld.*Demo$',content)
print(result)
print(result.group(1))#为了看看匹配的分组中是否是我所需要的
print(result.span())

输出结果

<re.Match object; span=(0, 40), match='Hello 1234567 World_This is a Regex Demo'>
1234567
(0, 40)

#(\d+) \d表示数字, + 表示一个或多个,括号就是将其作为一个分组

接着是两个比较关键的匹配方法

贪婪匹配
content = 'Hello 1234567 World_This is a Regex Demo'
result = re.match('^He.*(\d+).*Demo$',content)
print(result)
print(result.group(1))

输出结果

<re.Match object; span=(0, 40), match='Hello 1234567 World_This is a Regex Demo'>
7

#Python里数量词默认是贪婪的(在少数语言里也可能是默认非贪婪),总是尝试匹配尽可能多的字符
#贪婪模式下字符串查找会直接走到字符串结尾去匹配,如果不相等就向前寻找,这一过程称为回溯。

#上面的例子可以看出 .* 这样的前后搭配匹配 可以前后尝试尽可能多的匹配字符
非贪婪匹配
content = 'Hello 1234567 World_This is a Regex Demo'
result = re.match('^He.*?(\d+).*Demo$',content)
print(result)
print(result.group(1))

输出结果

<re.Match object; span=(0, 40), match='Hello 1234567 World_This is a Regex Demo'>
1234567

#非贪婪则相反,总是尝试匹配尽可能少的字符。在"*","?","+","{m,n}"后面加上?,使贪婪变成非贪婪。
#非贪婪模式下会自左向右查找,一个一个匹配不会出现回溯的情况。
匹配模式
content = '''Hello 1234567 World_This
is a Regex Demo
'''
result = re.match('^He.*?(\d+).*?Demo',content,re.S)
print(result.group(1))

匹配模式主要利用了re库中的re.S参数,这样就可以将字符串作为一个整体,在整体中进行匹配。

以上就是关于正则表达式的基本知识。看一下例子,知道大概就足够了。

豆瓣的正则表达式

在这里插入图片描述

首先进入豆瓣的top250排行榜,我们首先能看到的就是关于电影的内容。利用chrome浏览器右击检查打开审查元素,我们来观察一下这个网页的html大概构成。

在这里插入图片描述

我们将鼠标放到li标签上,可以看到左侧的一片区域都被标记了。说明这一块都是有关《肖申克的救赎》。

在这里插入图片描述

一步一步点开这个标签我们将鼠标放到每一个标签之上能看到,每一个标签都有一个与之对应的区域,这个时候我们就需要使用这些标签来构建正则表达式。

我们从每一个标签自上而下看下来。

依次是名次 片名 职员表 类型 星级 评价人数 热门短评这几个

比如名次去匹配

'<em class="">(\d+)</em>'
#因为名次是用数字表示的,先将一个标签内的数字用(\d+)来表示
'<em class="">(\d+)</em>.*?<span class=title">(.*?)</span>'
#当第一个标签完成之后,根据非贪婪匹配的规则 .*? 这样继续根据HTML标签的镶嵌继续向下搜寻。直到span标签结束。中间括号是我们需要匹配的内容

正则表达式的使用还是很简单的,只要找到我们需要的内容,利用非贪婪匹配进行前后选择就好了

下面的是一个已经匹配好的正则表达式。

'<em class="">(\d+)</em>.*?<span class="title">(.*?)</span>.*?<p class="">(.*?)</p>.*?<span class="rating_num" property="v:average">(.*?)</span>.*?<span>(.*?)</span>.*?<span class="inq">(.*?)</span>'

代码获取内容

接下来的步骤就与我之前的一篇博文的内容很相似了

python-对猫眼网的top100的爬取

首先需要定义一个函数去获取页面

import requests
import re
import json
from requests.exceptions import RequestException
import time
#得到网页源代码
def get_one_page(url):
    try:
        res=resquest.get(url)
        if res.status_code==200:
            return res.text
        return None
    except RequestException:
        return None

得到了网页源代码之后,需要利用正则表达式去匹配出我们需要的内容,并将它们放入到一个字典中。

def pares_one_html(html):
    regex='<em class="">(\d+)</em>.*?<span class="title">(.*?)</span>.*?<p class="">(.*?)</p>.*?<span class="rating_num" property="v:average">(.*?)</span>.*?<span>(.*?)</span>.*?<span class="inq">(.*?)</span>'
    pattern=re.compile(regex,re.S)#re.compile()编译正则表达式模式
    items=re.findall(pattern,html)#返回的是一个list对象
    for item in items:
        content=""
        for every_list in item[2].split():
            #split()通过指定分隔符对字符串进行切片,因为职员表处有些标签需要我们进行处理
            content=content+"".join(every_list)
        content=re.sub('&nbsp;',' ',content)
        content=re.sub('<br>',' ',content)
        #删除空格和<br>这些多余的部分
        #将获取到的list放到dict字典中
        dict={
            "index":item[0],
            "name":item[1],
            "describe":content,
            "star":item[3],
            "evaluate":item[4],
            "title":item[5]
        }
        print(dict)
        #此时先打印看一下,是否数据是正确的
        #将数据写入文本中
        with open('doubanMovie.txt','a',encoding='utf-8') as f:
            f.write(json.dumps(dict,ensure_ascii=False)+'\n')

此时还有两个问题,我们此时只是能将第一个页面的数据爬取下来,这时候我们得分析一下这个url在切换页面时,它是怎么变化的。

在这里插入图片描述

在这里插入图片描述

https://movie.douban.com/top250这是豆瓣top250的第一页

转到第二页,第三页可以看到网页的变化

https://movie.douban.com/top250?start=25&filter= 第二页

https://movie.douban.com/top250?start=50&filter= 第三页

url中的参数start={} 这个数在不断的变化,而且规律是每次隔25个,说明这就是我们需要的。

if __name__ == '__main__':
    urls=['https://movie.douban.com/top250?start={}&filter='.format(str(i)) for i in range(0,250,25)]
    for url in urls:
        html=get_one_page(url)
        parse_one_html(html)
        time.sleep(2)

最后将url放在一个列表中,利用for循环去将所有这些网页循环将数据爬取出来。

最后展示一下

在这里插入图片描述

在这里插入图片描述

python的学习中,爬虫只要有了基本的知识之后就可以慢慢尝试了,而且我觉得爬虫是最容易有自豪感的。

之前对猫眼的爬取用到了基本的Requests和beautifulsoup,接下来还会在写一篇关于Scrapy的基础知识,这个我认为是爬虫的总统山…但是我也还在摸索中

接着刷电影去了…(●’◡’●)

猜你喜欢

转载自blog.csdn.net/skrskr66/article/details/85228193