爬取猫眼前一百电影数据

记录一下python爬虫的学习过程

看着B站的视频学习一下爬虫,自己没事扒点小说下来看看也是不错的

先从简单的一步步来

跟着视频做了一个简单的从猫眼电影上扒下来的一个排名,猫眼电影的Top100

一、获取url

首先,我们当然要先拿到我们想要请求的地址才行阿!
我们想要请求的地址是http://maoyan.com/board/4?offset=0,而且我们发现每一次请求只是返回十个电影
我们通过对offset参数的改变可以,拿到我们想要的排名的数据

二、分析网页结构

通过网页的源码分析,可以发现一页的我们需要提取的内容被包含在一个如下结构中:

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
<dl class="board-wrapper">
<dd>
<i class="board-index board-index-1">1</i>
<a href="/films/1203" title="霸王别姬" class="image-link" data-act="boarditem-click" data-val="{movieId:1203}">
<img src="//ms0.meituan.net/mywww/image/loading_2.e3d934bf.png" alt="" class="poster-default" />
<img data-src="http://p1.meituan.net/movie/20803f59291c47e1e116c11963ce019e68711.jpg@160w_220h_1e_1c" alt="霸王别姬" class="board-img" />
</a>
<div class="board-item-main">
<div class="board-item-content">
<div class="movie-item-info">
<p class="name"><a href="/films/1203" title="霸王别姬" data-act="boarditem-click" data-val="{movieId:1203}">霸王别姬</a></p>
<p class="star">
主演:张国荣,张丰毅,巩俐
</p>
<p class="releasetime">上映时间:1993-01-01(中国香港)</p> </div>
<div class="movie-item-number score-num">
<p class="score"><i class="integer">9.</i><i class="fraction">6</i></p>
</div>

</div>
</div>

</dd>
<dd>
<i class="board-index board-index-2">2</i>
<a href="/films/1297" title="肖申克的救赎" class="image-link" data-act="boarditem-click" data-val="{movieId:1297}">
<img src="//ms0.meituan.net/mywww/image/loading_2.e3d934bf.png" alt="" class="poster-default" />
<img data-src="http://p0.meituan.net/movie/283292171619cdfd5b240c8fd093f1eb255670.jpg@160w_220h_1e_1c" alt="肖申克的救赎" class="board-img" />
</a>
<div class="board-item-main">
<div class="board-item-content">
<div class="movie-item-info">
<p class="name"><a href="/films/1297" title="肖申克的救赎" data-act="boarditem-click" data-val="{movieId:1297}">肖申克的救赎</a></p>
<p class="star">
主演:蒂姆·罗宾斯,摩根·弗里曼,鲍勃·冈顿
</p>
<p class="releasetime">上映时间:1994-10-14(美国)</p> </div>
<div class="movie-item-number score-num">
<p class="score"><i class="integer">9.</i><i class="fraction">5</i></p>
</div>

</div>
</div>

</dd>
</dl>

可以发现,每一个电影信息都被包围在一个

的标签当中

三、开始撸代码

1.我们先定义一个抓取网页代码的方法

1
2
3
4
5
6
7
8
9
#利用requests库,通过传入的url获取想要的网页数据
def get_one_page(url):
try:
response = requests.get(url)
if response.status_code == 200:
return response.text
return None
except RequestException:
return None

2.解析获取到的网页数据

通过上一个方法我们已经获取到了网页的数据,现在当然是解析这些数据,从其中获取我们想要的部分咯

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
                <dd>
<i class="board-index board-index-1">1</i>
<a href="/films/1203" title="霸王别姬" class="image-link" data-act="boarditem-click" data-val="{movieId:1203}">
<img src="//ms0.meituan.net/mywww/image/loading_2.e3d934bf.png" alt="" class="poster-default" />
<img data-src="http://p1.meituan.net/movie/20803f59291c47e1e116c11963ce019e68711.jpg@160w_220h_1e_1c" alt="霸王别姬" class="board-img" />
</a>
<div class="board-item-main">
<div class="board-item-content">
<div class="movie-item-info">
<p class="name"><a href="/films/1203" title="霸王别姬" data-act="boarditem-click" data-val="{movieId:1203}">霸王别姬</a></p>
<p class="star">
主演:张国荣,张丰毅,巩俐
</p>
<p class="releasetime">上映时间:1993-01-01(中国香港)</p> </div>
<div class="movie-item-number score-num">
<p class="score"><i class="integer">9.</i><i class="fraction">6</i></p>
</div>

</div>
</div>

</dd>

从上面的数据中提取我们想要的数据,如:imagetitleactortimescoreindex
下面是具体的方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#通过正则表达式匹配想提取的数据
def parse_one_page(html):
pattern = re.compile('<dd>.*?board-index.*?>(\d+)</i>.*?data-src="(.*?)".*?name"><a'
+ '.*?>(.*?)</a>.*?star">(.*?)</p>.*?releasetime">(.*?)</p>'
+ '.*?integer">(.*?)</i>.*?fraction">(.*?)</i>.*?</dd>',re.S)
items = re.findall(pattern,html)
for item in items:
yield {
'index':item[0],
'image':item[1],
'title':item[2],
'actor':item[3].strip()[3:],
'time':item[4].strip()[5:],
'score':item[5] + item[6]
}

这里补充一些关于正则表达式:上面那个表达式中用括号括起来的部分就是我们要提取的数据,写好正则表达式之后用re.findall()方法找出所有符合条件的数据
该方法会返回所有符合条件的数据,我们利用yield将其返回

将获取到的数据存入文件当中

当然,标准的做法是将数据存入数据库中,不过还是从简单的开始做起,所以选择了存入文件中

这里,我们定义一个将数据存入文件的方法

1
2
3
4
#将数据保存到文件中,这里的content是一个字典
def write_to_file(content):
with open('result.txt','a',encoding='utf-8') as f:
f.write(json.dumps(content,ensure_ascii=False) + '\n')

由于我们要存入中文字,所以open()方法中要加入encoding='utf-8'
dumps()方法中要加入ensure_ascii=False参数
json.dumps()方法可以将字典转化为字符串

拼接url

之前我们说过,要想获取榜单的不同位置,我们需要改变url中offset参数的值
我们可以通过for循环加字符串拼接做到这一点

1
2
3
url = 'http://maoyan.com/board/4?offset='
for offset in range(0,100,10):
newUrl = url + str(offset)

我们再将前面的方法组合一下,得到main()方法

1
2
3
4
5
6
7
8
def main():
url = 'http://maoyan.com/board/4?offset='
for offset in range(0,100,10):
newUrl = url + str(offset)
html = get_one_page(newUrl)
for item in parse_one_page(html):
print(item)
write_to_file(item)

到这里,这一个简单的爬虫就算完成了,你只要运行一下,就可以生成一个含有前一百名电影信息的result.txt文件了。

四、最后

整个源代码为:

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
import json
import requests
from requests.exceptions import RequestException
import re

#利用requests库,通过传入的url获取想要的网页数据
def get_one_page(url):
try:
response = requests.get(url)
if response.status_code == 200:
return response.text
return None
except RequestException:
return None

#通过正则匹配获取电影的信息
def parse_one_page(html):
pattern = re.compile('<dd>.*?board-index.*?>(\d+)</i>.*?data-src="(.*?)".*?name"><a'
+ '.*?>(.*?)</a>.*?star">(.*?)</p>.*?releasetime">(.*?)</p>'
+ '.*?integer">(.*?)</i>.*?fraction">(.*?)</i>.*?</dd>',re.S)
items = re.findall(pattern,html)
for item in items:
yield {
'index':item[0],
'image':item[1],
'title':item[2],
'actor':item[3].strip()[3:],
'time':item[4].strip()[5:],
'score':item[5] + item[6]
}

#将数据保存到文件中
def write_to_file(content):
with open('result.txt','a',encoding='utf-8') as f:
f.write(json.dumps(content,ensure_ascii=False) + '\n')

def main():
url = 'http://maoyan.com/board/4?offset='
for offset in range(0,100,10):
newUrl = url + str(offset)
html = get_one_page(newUrl)
for item in parse_one_page(html):
print(item)
write_to_file(item)

if __name__ == '__main__':
main()

如果想加快速度的话,可以使用多线程加载
源代码为:

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
#This is Thread version
import json
from multiprocessing.pool import Pool

import requests
from requests.exceptions import RequestException
import re

def get_one_page(url):
try:
response = requests.get(url)
if response.status_code == 200:
return response.text
return None
except RequestException:
return None

def parse_one_page(html):
pattern = re.compile('<dd>.*?board-index.*?>(\d+)</i>.*?data-src="(.*?)".*?name"><a'
+ '.*?>(.*?)</a>.*?star">(.*?)</p>.*?releasetime">(.*?)</p>'
+ '.*?integer">(.*?)</i>.*?fraction">(.*?)</i>.*?</dd>',re.S)
items = re.findall(pattern,html)
for item in items:
yield {
'index':item[0],
'image':item[1],
'title':item[2],
'actor':item[3].strip()[3:],
'time':item[4].strip()[5:],
'score':item[5] + item[6]
}

def write_to_file(content):
with open('resultUpgrade.txt','a',encoding='utf-8') as f:
f.write(json.dumps(content,ensure_ascii=False) + '\n')

def main(offset):
url = 'http://maoyan.com/board/4?offset='
newUrl = url + str(offset)
html = get_one_page(newUrl)
for item in parse_one_page(html):
print(item)
write_to_file(item)

if __name__ == '__main__':
pool = Pool()
pool.map(main,[i*10 for i in range(10)])