爬猫眼TOP100电影之正则表达式

背景

之前写过一个爬虫,爬取比特币官网的交易数据,用的是网页解析库(Python的BeautifulSoup)解析页面内容。最近学习了基础的正则表达式,所以实践一波用正则解析HTML,爬取猫眼榜单上TOP100榜的电影,包括电影排名、电影名、主演、上映时间以及评分信息。

爬虫基础回顾

基本流程

  • 发起请求。模拟浏览器发送一个request,请求可以包含额外的头信息,等待服务器响应。
    说明: 在浏览器输入地址,回车,就是一个请求。请求方式主要有getpost两种类型;请求的URL,统一资源定位符,网页的一张图片,一个视频或者是文档都由URL确定;请求头,包含Cookies,host,User-Agent等信息;请求体,额外携带的一些信息,如表单提交的表单数据。

  • 获取响应内容。正常情况下服务器返回一个response,其中包含要爬取的页面内容信息,形式可以是HTML,Json或者图片视频类的二进制数据。
    说明: 服务器根据请求,返回数据到浏览器显示,就是一个响应。响应状态,有多种,200是OK、301重定向、404找不到、502服务器错误等;响应头,包含内容类型、内容长度、服务器信息等;响应体,主要是包含请求的资源内容,如图片、视频等。

  • 解析内容。对HTML可用正则表达式或者网页解析库解析,对Json可以转为Json对象解析,对二进制数据,做保存或者进一步处理。
    说明: 解析方式有多种,对于解析库的选择可根据爬取的网页具体情况具体选择。常见的解析方式除了正则外,还有一些解析库,如BeautifulSoupXPathPyQuery等。

  • 保存数据。形式很多,可存文本,特定格式的文件,也可以保存至数据库。

注:有时爬取到的内容都是HTML,CSS和JavaScript代码,想要的数据不在抓取的内容中,这种动态网页的情况,待之后遇到再记录。

准备工作

  • 分析要爬取电影的页面信息,获取到数据来源(正确的页面链接)
    如下图所示,猫眼排行榜TOP100榜的页面信息:

页面URL

在要获取的电影信息上面,【鼠标右击】,点击【检查】,进入页面分析模式,切到【Network】,点击【Name】下的链接,在【Response】下确认页面结构中是否出现所需信息,若没出现就换下一个链接,直到找到正确的链接,然后切到【Headers】,找到该页面的链接,请求方式等信息。

  • 定位要获取的信息具体在页面结构中的哪个位置
    鼠标放在要找元素上方【右击】,点击【检查】,切到【Element】,即可定位到它所在的标签,发现要获取的每条数据都在<dd></dd>标签内。
    定位

  • 分析不同页面的URL之间的关系
    点击页面翻页按钮,分析页面URL之间的变化关系,发现URL只有最后的offset在改变,并且每次递增10,排行榜第一页offset为0,第二页offset为10,以此类推。
    页面offset

代码

先导入所需模块

1
2
3
import requests
import re
import pandas as pd

面向对象编程,定义一个爬虫类,里面的每一个类方法就是爬虫的4个基本流程之一。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
class MYSpider(object):
'''
定义一个爬虫类
'''
def __init__(self,base_url,url_headers):
self.base_url = base_url
self.headers = url_headers

def get_onePage(self,start_num):
'''
获取第一页内容
'''
url = self.base_url.format(start_num)
response = requests.get(url=url,headers=self.headers)
if response.status_code == 200:
return response.content.decode('utf-8')
else:
return None

def parse_onePage(self,html):
'''
解析数据
'''
#正则获取排名、电影名、主演、上映时间、评分
#用re的compile()模块创建模式对象
pattern = re.compile('<dd>.*?board-index.*?>(\d+).*?movie-item-info.*?>.*?<a'
+'.*?title="(.*?)".*?star.*?>\s+主演:(.*?)\s+</p>.*?releasetime.*?>上映时间:(.*?)</p>'
+'.*?integer.*?>(\d+\.)</i>.*?fraction.*?>(\d+)</i>.*?</dd>',re.S)
result = re.findall(pattern,html)
#print(result)
return result

def save_data(self,data):
'''
保存数据
'''
rank=[];name=[];star=[];time=[];score= []

for value in data:
rank.append(value[0])
name.append(value[1])
star.append(value[2])
time.append(value[3].strip()[:10])
score.append(value[4]+value[5])

rank_col = pd.Series(rank)
name_col = pd.Series(name)
star_col = pd.Series(star)
time_col = pd.Series(time)
score_col = pd.Series(score)
movie_data = pd.concat([rank_col,name_col,star_col,time_col,score_col],axis=1)
#将数据通过pandas的to_csv方法写入到csv文件
movie_data.to_csv('./moviedata.csv',mode='a',index=False,header=False,encoding='gbk')

调用爬虫类的方法,完成10个页面的请求、解析和保存工作。这里每个页面URL之间的关系通过前面的准备工作分析得出,即offset每次递增10。
请求头headers的内容是相对固定的,是模拟不同的浏览器对服务器发起请求。

1
2
3
4
5
6
7
8
if __name__ == "__main__":
base_url = 'https://maoyan.com/board/4?offset={}'
headers = {"User-Agent":'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36(KHTML, like Gecko) Chrome/74.0.3729.131 Safari/537.36'}
myspider = MYSpider(base_url,headers)
for i in range(0,100,10):
html = myspider.get_onePage(i)
result_data = myspider.parse_onePage(html)
myspider.save_data(result_data)

得到的数据存储在moviedata.csv文件中,查看爬取结果,如下:
csv结果

-------------完-------------