检查网页源代码

首先让我们来检查豆瓣top250的源代码,一切网页爬虫都需要从这里开始。F12打开开发者模式,在元素(element)页面通过Ctrl+F直接搜索你想要爬取的内容,然后就可以开始编写正则表达式了。

如下是我们将要爬取内容的html局部区域:

<div class="item">
<div class="pic">
<em class="">1</em>
<a href="https://movie.douban.com/subject/1292052/">
<img width="100" alt="肖申克的救赎" src="https://img2.doubanio.com/view/photo/s_ratio_poster/public/p480747492.webp" class="">
</a>
</div>
<div class="info">
<div class="hd">
<a href="https://movie.douban.com/subject/1292052/" class="">
<span class="title">肖申克的救赎</span>
<span class="title">&nbsp;/&nbsp;The Shawshank Redemption</span>
<span class="other">&nbsp;/&nbsp;月黑高飞(港) / 刺激1995(台)</span>
</a>
<span class="playable">[可播放]</span>
</div>
<div class="bd">
<p class="">
导演: 弗兰克·德拉邦特 Frank Darabont&nbsp;&nbsp;&nbsp;主演: 蒂姆·罗宾斯 Tim Robbins /...<br>
1994&nbsp;/&nbsp;美国&nbsp;/&nbsp;犯罪 剧情
</p>
<div class="star">
<span class="rating5-t"></span>
<span class="rating_num" property="v:average">9.7</span>
<span property="v:best" content="10.0"></span>
<span>2668670人评价</span>
</div>
<p class="quote">
<span class="inq">希望让人自由。</span>
</p>
</div>
</div>
</div>

当然,在Chrome中页面是这样的:

匹配正则表达式

<em class="">1</em>这显然是‘’索引‘’可以用于匹配序号

相应正则表达式为:

<em class="">(\d+)</em>

其中\d+的含义是匹配1个及以上的数字

正则表达式详解请看:正则表达式完整入门教程,含在线练习

正则表达式速查表请看:正则表达式速查表

<a href="https://movie.douban.com/subject/1292052/">这个表示的是标题对应的超链接,也就是对应电影的详情页,如果我们要做进一步的内容爬取,这个链接也是值得保存的。

这里介绍一下re.S参数,它可以让我们跨行匹配正则表达式。而且我们知道,正则表达式越详细,匹配的精确度就越高,于是我们可以将上下两行一起匹配。

<em class="">1</em>
<a href="https://movie.douban.com/subject/1292052/">

相应的正则表达式为:

'<em class="">(\d+)</em>.*?<a href="(.*?)">.*?'

然后我来解释下为什么我们要加括号(),这是因为,有的时候我们想要的不是每一个存在变化的变量,它们仅仅需要作为通配符来使用,于是我们将需要返回的匹配值加上括号作为返回值,未加括号的正则表达式匹配的值不会被返回。上面的.*?就是不会被返回的正则表达式。

接下来看看我们的完整正则表达式吧:

pattern = re.compile(
'<em class="">(\d+)</em>.*?<a href="(.*?)">.*?' +
'<img width="100" alt=".*?" src="(.*?)" class=""' +
'>.*?<span class="title">(.*?)</span>.*?<span ' +
'class="other">&nbsp;/&nbsp;(.*?)</span>.*?<div ' +
'class="bd">.*?<p class="">.*?导演: (.*?)&nbsp.*?<br>' +
'.*?(\d{4})&nbsp;/&nbsp;(.*?)&nbsp;/&nbsp;(.*?)\n' +
'.*?</p>.*?<span class="rating_num" property="v:' +
'average">(.*?)</span>',
re.S)

正则表达式中.表示任意字符;*表示前置字符任意次数;?表示前置字符可有可无。

这个号,即是常用的连接字符串的用法。我们可以发现,上述表达式一共有10个括号(),也就是说最终会在一个item中返回10个值,以列表(数组)形式。

  • 正则中没有括号时,返回的是 list,list的元素是 str ;
  • 正则中有括号时,返回的是 list,list的元素是 tuple ,tuple 中的各项对应的是括号中的匹配结果

下面我们来认识一下re的几个库函数:

  • re.compile 是预编译正则表达式函数,是用来优化正则的,它将正则表达式转化为对象

  • re.compile 函数用于编译正则表达式,生成一个 Pattern 对象,pattern 是一个字符串形式的正则表达式

  • pattern 是一个匹配对象( Regular Expression),它单独使用就没有任何意义,需要和findall(), search(), match()搭配使用。

  • 使用re.S参数以后,正则表达式会将这个字符串作为一个整体,将“\n”当做一个普通的字符加入到这个字符串中,在整体中进行匹配,而不是在一行内进行匹配。

  • re.findall返回string中所有与pattern相匹配的全部字串,返回形式为数组

完整代码

导入包

# json包
import json
#正则表达式包
import re
import requests
from requests import RequestException

定义获取html函数

#函数:获取一页html
def get_one_page(url):
try:
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36'
}
# Response对象返回包含了整个服务器的资源
# Response对象的属性,有以下几种
# r.status_code: HTTP请求的返回状态,200表示连接成功,404表示失败
# 2.r.text: HTTP响应内容的字符串形式,即,url对应的页面内容
# 3.r.encoding:从HTTP header中猜测的响应内容编码方式
# 4.r.apparent_encoding:从内容中分析出的响应内容编码方式(备选编码方式)
# 5.r.content: HTTP响应内容的二进制形式
response = requests.get(url, headers=headers, timeout=1000)
if response.status_code == 200:
return response.text
except requests.exceptions.RequestException as e:
print(e)

定义解析html函数【正则】

#函数:解析一页html
def parse_one_page(html):
pattern = re.compile(
'<em class="">(\d+)</em>.*?<a href="(.*?)">.*?' +
'<img width="100" alt=".*?" src="(.*?)" class=""' +
'>.*?<span class="title">(.*?)</span>.*?<span ' +
'class="other">&nbsp;/&nbsp;(.*?)</span>.*?<div ' +
'class="bd">.*?<p class="">.*?导演: (.*?)&nbsp.*?<br>' +
'.*?(\d{4})&nbsp;/&nbsp;(.*?)&nbsp;/&nbsp;(.*?)\n' +
'.*?</p>.*?<span class="rating_num" property="v:' +
'average">(.*?)</span>',
re.S)
#使用re.S参数以后,正则表达式会将这个字符串作为一个整体,将“\n”当做一个普通的字符加入到这个字符串中,在整体中进行匹配,而不是在一行内进行匹配。
#re.findall返回string中所有与pattern相匹配的全部字串,返回形式为数组
#上述pattern正好有10个括号
items = re.findall(pattern, html)
for item in items:
yield {
'index': item[0],
'page_src': item[1],
'img_src': item[2],
'title': item[3],
'other_title': item[4],
'director': item[5],
'release_date': item[6],
'country': item[7],
'type': item[8],
'rate': item[9],
}

定义保存内容函数

#函数:将内容写入文件
def write_to_file(content):
with open('douban_movie_rankings.txt', 'a', encoding='utf-8') as f:
f.write(json.dumps(content, ensure_ascii=False) + '\n')

定义主函数

#主控函数
def main():
#用于翻页
for offset in range(10):
#获取网址
url = f'https://movie.douban.com/top250?start={offset * 25}&filter='
#获取html文件
html = get_one_page(url)
for item in parse_one_page(html):
print(item)
write_to_file(item)

定义魔法函数

if __name__ == '__main__':
main()

原创作者:孤飞-博客园

原文链接:https://www.cnblogs.com/ranxi169/p/16565717.html

最新文章

  1. svn web页面管理svnadmin部署
  2. 使用ArcGIS JavaScript API 3.18 加载天地图
  3. C++11 变长模版和完美转发实例代码
  4. iOS---NSAutoreleasePool自动释放原理及详解
  5. MongoDB,客户端工具备份数据库
  6. Diophantus of Alexandria[HDU1299]
  7. Shell 脚本基本操作练习
  8. myeclipes使用过程中的错误解决方案
  9. [C#]6.0新特性浅谈
  10. Carthage的安装和使用
  11. CCF-201403-3-命令行选项
  12. Springboot 之 解决IDEA读取properties配置文件的中文乱码问题
  13. UNIX网络编程——使用select函数的TCP和UDP回射服务器程序
  14. Django_cookie_session
  15. python 视图 (FBV、CBV ) 、Request 和Response对象 、路由系统
  16. IO通信模型(三)多路复用IO
  17. Java 常用知识点
  18. 如何解决串session:
  19. kali linux revealed mastering the penetration testing distribution
  20. Linux中断处理(二)

热门文章

  1. 爬取豆瓣喜剧类热门TOP60的电影
  2. Fail2ban 术语
  3. Seata源码分析——SessionManager
  4. 如何为Java面试准备项目经验
  5. springcloud 断路器
  6. 物联网lora模块应用案例和LoRawan网关通信技术
  7. springboot引入mybatis遇到的坑
  8. python中 OS模块中 os.path.join() 函数用法简介
  9. 31.Squid缓存代理服务器应用
  10. 重学ES系列之新增的几个循环方法