Python——爬虫爬取豆瓣TOP250的电影

     阅读:28

前言

忽然强烈的预感自己会很快用得上爬虫,这两天稍微学了一下python的爬虫,就想找个案例练一下手,很不幸,豆瓣被选中了,谁叫服务器渲染的HTML更有意思呢?
对不住了豆瓣

准备

用到的包有

requests

用于发送请求与接收结果

re

用来使用正则表达式

csv

用来将获得的数据写入csv文件中,在后面的数据处理更加方便读取

思路

下面开始讲解:
注意:思路不是程序编写的顺序,而且从大局的观念起步,且最后也有完整可以直接运行的代码
一、网站信息读取
1、首先获取需要爬取页面的URL,这里就是豆瓣了
豆瓣电影TOP250
2、通过查看豆瓣的网页源代码发现,该网页是由服务器渲染的HTML,所以选择使用正则(这里还有很多方法,这里先用正则尝试)来处理豆瓣源代码
3、通过chrome自带的抓包工具发现请求方式为get
在这里插入图片描述
4、由于豆瓣经常被爬,所以它设置了反爬🤣,不过仅是对UA的检查,找到一般浏览器访问豆瓣网页所携带的UA,写入到requests中即可,还是刚才抓包的文件,最下面有UA即User-Agent在这里插入图片描述
5、接下来写正则re的预编译,像是豆瓣这样的大网站,前端编写的规定是很严格的,比如有电影信息的div中的class等是与其他构建网页组件不一样的,这也方便了正则的应用。
如该代码,电影名都在span这个标签里面,而且有特定的class,故此凭借这个span与class可以快速定位电影名称与获取,在python的re中,结果是由字典存放的,其中

?P<name>

即为字典的key,源代码中的数据即为字典中的value

<span class="title">(?P<name>.*?)</span>

值得注意的是在正则里面“.”是可以匹配除了换行符\n以为任意字符的,但在HTML代码里面有大量的换行符,好在re.compile可以使用一个参数re.S可以使得“.”也匹配到换行符\n
6、豆瓣像大多数网站一样,采取了分页的显示,但是从第二页第三页的url中仅能看到起始参数start,本人猜测大概会有end参数,但是我还是继续选择了麻烦的仅有start的参数,算是考验自己,通过for循环来获取

# 因该页面仅有起始数不能范围获取,
#设置变量page表示为其实抓取的页面
for i in range(0, 250, 25):

二、csv文件写入
1、这里没什么好说的,不过需要注意,这里的参数mode使用的是a+即追加写入,而不是w覆盖写入,这是因为这里是循环获取网页信息并不是一次性把数据全部请求下来,并且windows电脑需要加上encoding的编码,否则默认是gbk,newline是因为,文件的open会自动换行,而csvwritter也会自动换行,使得newline=“”可以忽略文件的open的换行

# 设置接收的csv文件
    f = open('data.csv', mode='a+', encoding='utf-8', newline='')
    # 创建写入器
    csvwritter = csv.writer(f)

2、最后一定要注意将请求与文件流都关闭

# 关闭链接,防止被拉黑
    resp.close()
# 关闭文件流
    f.close()

最后附上完整代码,并有大量注释

# 拿到页面源代码  requests
import requests
# 通过re来进一步提取有效信息 re
import re
# csv处理
import csv

# 需要爬取的url
url = 'https://movie.douban.com/top250'
# 设置请求头的UA
headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.54 Safari/537.36'
}
# 预编译re
obj = re.compile(
    r'<li>.*?<div class="item">.*?<span class="title">(?P<name>.*?)</span>'
    r'.*?<p class="">.*?<br>(?P<year>.*?)&nbsp.*?<span class="rating_num" property="v:average">(?P<score>.*?)</span>.*?'
    r'<span>(?P<num>.*?)人评价</span>',
    re.S)
# 设置接收的csv文件
f = open('data.csv', mode='a+', encoding='utf-8', newline='')
# 因该页面仅有起始数不能范围获取,设置变量page表示为其实抓取的页面
for i in range(0, 250, 25):
    # 请求参数
    data = {
        # start=25&filter=
        'start': i,
        'filter': ''
    }
    # 获取数据
    resp = requests.get(url, headers=headers, params=data)
    # 转为字符串
    page_content = resp.text
    # 关闭链接,防止被拉黑
    resp.close()
    # 接收正则的结果
    ret = obj.finditer(page_content)
    # 创建写入器
    csvwritter = csv.writer(f)
    # 循环结果
    for i in ret:
        dic = i.groupdict()
        dic['year'] = dic['year'].strip()
        csvwritter.writerow(dic.values())
# 关闭文件流
f.close()

获取的csv数据(部分)
在这里插入图片描述

醉后不知天在水,满船清梦压星河。