爬取猫眼TOP100榜#
1. 爬取流程#
主要有以下四步:
- 爬取单页内容:利利⽤用requests请求⽬目标站点,得 到单个⽹网⻚页HTML代码,返回结果。
- 正则表达式分析:根据HTML代码分析得到电影的 名称、主演、上映时间、评分、 图⽚片链接等信息。
- 保存至文件:通过⽂文件的形式将结果保存,每 一部电影一个结果一行Json字符串,图片保存成jpg格式。
- 开启循环及多线程:对多⻚页内容遍历,开启多线程提 ⾼高抓取速度。
2. 具体分析#
1. 爬取单页内容#
观察到每页的页数有offset 这个变量来控制,100条数据,10页,每页10条,所以offset从0到9。以offset作为变量,先爬取单页,然后循环爬取所有页。
1
2
3
4
5
6
7
8
9
10
11
12
13
| base_url = 'https://maoyan.com'
url = 'https://maoyan.com/board/4?offset=' + str(offset)
html = get_one_page(url)
def get_one_page(url):
try:
response = requests.get(url)
if response.status_code == 200:
return response.text
else:
return None
except RequestException:
return None
|
爬取部分通过requests中的get方法来实现,这是基本套路。正常情况下返回200状态码,非正常情况下返回None
2. 正则表达式分析#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| def parse_one_page(base_url, html):
pattern = re.compile('<dd>.*?<i.*?board-index.*?">(\d+)</i>.*?href="(.*?)".*?data-src="(.*?)".*?data-val=.*?>(.*?)</a>.*?star">(.*?)</p>'
'.*?releasetime">(.*?)</p>.*?score.*?integer">(.*?)</i>.*?fraction">(.*?)</i>.*?</dd>', re.S)
items = re.findall(pattern, html)
for item in items:
yield {
'index': item[0],
'url': base_url + item[1],
'image': item[2],
'title': item[3],
'actor': item[4].strip()[3:],
'time': item[5].strip()[5:],
'score': item[6] + item[7]
}
|
这部分主要是正则表达式的书写,对于学爬虫的童鞋,正则是基本功,既基础又重要,不会的自行谷歌。虽然对于网页的解析有很多中方法,比如BeautifulSoup,PyQuery等,会一些网页前端的知识就能掌握,但是别人问你学了爬虫会正则吗,你好意思说不会吗?模式串写好了,然后通过findall方法爬取所有符合模式串的字符串,并返回给items,这是一个列表。最后通过yield生成器生成一个字典返回
3. 保存文件#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
| def write_to_file(content):
with open('result.txt','a', encoding='utf-8') as f:
# 当在下面打印出来是中文汉字,而写成的文件出现编码格式则在json转换时出问题了
f.write(json.dumps(content, ensure_ascii=False) + '\n') # 每行字典转换成json,再加上'\n',最后写入到文件
def download_image(url):
print('Downloading', url)
try:
response = requests.get(url)
if response.status_code == 200:
save_image(response.content)
return None
except ConnectionError:
return None
def save_image(content):
file_path = '{0}/{1}.{2}'.format(os.getcwd() + r'/images/', md5(content).hexdigest(), 'jpg')
print(file_path)
if not os.path.exists(file_path):
with open(file_path, 'wb') as f:
f.write(content)
f.close()
|
这部分其实是很简单,非常套路,不过要注意的是文件的编码问题,中文编码要用’utf-8’,当让还有其他编码,源码中可以找到。
4. 开启循环及多线程#
1
2
| pool = Pool()
pool.map(main, [i*10 for i in range(10)])
|
就是开一进程池,然后用调用map方法,写上循环次数搞定。
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
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
| import requests
from requests.exceptions import RequestException
import re
import json
from multiprocessing import Pool # 通过进程池实现多进程抓取
import os
from hashlib import md5
def get_one_page(url):
try:
response = requests.get(url)
if response.status_code == 200:
return response.text
else:
return None
except RequestException:
return None
def parse_one_page(base_url, html):
pattern = re.compile('<dd>.*?<i.*?board-index.*?">(\d+)</i>.*?href="(.*?)".*?data-src="(.*?)".*?data-val=.*?>(.*?)</a>.*?star">(.*?)</p>'
'.*?releasetime">(.*?)</p>.*?score.*?integer">(.*?)</i>.*?fraction">(.*?)</i>.*?</dd>', re.S)
items = re.findall(pattern, html)
for item in items:
yield {
'index': item[0],
'url': base_url + item[1],
'image': item[2],
'title': item[3],
'actor': item[4].strip()[3:],
'time': item[5].strip()[5:],
'score': item[6] + item[7]
}
def write_to_file(content):
with open('result.txt','a', encoding='utf-8') as f:
# 当在下面打印出来是中文汉字,而写成的文件出现编码格式则在json转换时出问题了
f.write(json.dumps(content, ensure_ascii=False) + '\n') # 每行字典转换成json,再加上'\n',最后写入到文件
def download_image(url):
print('Downloading', url)
try:
response = requests.get(url)
if response.status_code == 200:
save_image(response.content)
return None
except ConnectionError:
return None
def save_image(content):
file_path = '{0}/{1}.{2}'.format(os.getcwd() + r'/images/', md5(content).hexdigest(), 'jpg')
print(file_path)
if not os.path.exists(file_path):
with open(file_path, 'wb') as f:
f.write(content)
f.close()
def main(offset):
base_url = 'https://maoyan.com'
url = 'https://maoyan.com/board/4?offset=' + str(offset)
html = get_one_page(url)
# print(html)
for item in parse_one_page(base_url, html):
print(item)
write_to_file(item)
download_image(item['image'])
if __name__ == '__main__':
# for i in range(10):
# main(i*10)
# 先构造一个进程池,然后使用map方法,让进程进入进程池
pool = Pool()
pool.map(main, [i*10 for i in range(10)])
|