一、网站介绍
本次案例选用的网站是由崔先生(崔庆才)所维护的网站,今天的案例是也是网站中的一部分。
https://ssr1.scrape.center/
二、基础模块
本次用到的模块有:
1、json
本章会用到json.dump()方法,将数据保存成文本格式,用于数据的保存
2、requests
本章用到的数据请求方法主要采用requests.get()方法来请求
3、multiprocessing
创立多线程池,用于加快爬虫速度
4、urllib
基本不用urllib请求数据,太麻烦。但urljoin来拼接url还是不错的
5、os
系统库,用于创建文件夹
三、网站解析
本次的网站是一个非常基础的没有加密的网站,主要看一下它的数据位置以及翻页规则。
首先我们在电影信息块中可以看到蕴含着一个url后缀
点进电影详情后发现电影详情的url是原url与这个url后缀拼接而成的。
而它的翻页规则也很简单,是在原url的基础上加/page/页数
至此我们完成了对网站结构的解析
四、爬取准备
了解网站的结构后,接下来要进行数据爬取,首先是先得到不同页数的url的文本内容
total_page = 10
#如果网页请求成功则范围网页请求内容
def scrape_page(url):
try:
response = requests.get(url)
if response.status_code == 200:
return response.text
except:
raise
#得到不同页的url
def scrape_index(page):
page = str(page)
index_url = base_url+"page/" + page
return scrape_page(index_url)
for page in range(1,total_page + 1):
index_html = scrape_index(page)
得到不同页数的url之后,我们要得到每一页电影元素的详情页url后缀,并生成new_url返回
def parse_index(html):
detail_url = re.findall(r'<a data-v-7f856186="" href="(.*?)" class', html, re.S)
for item in detail_url:
new_url = urljoin(base_url,item)
yield new_url
deatil_urls = parse_index(index_html)
通过
for url in detail_urls:
print(url)
我们得到得数据应该是这样的
每一个url都是一个完整的电影详情页。此时已经完成了得到所有要解析网站的url了
接下来将进行数据解析的部分。网站很简单想怎么解析就怎么解析,但本次我采用与书上相同的方法进行了正则解析。并返回了一个json格式
def parse_detail(html):
img_pattern = re.compile('class="item.*?src="(.*?)".*?class="cover">',re.S)
img = re.search(img_pattern,html).group(1) if re.search(img_pattern,html) else None
name_pattern = re.compile('<h2 data-v-63.*?>(.*?)</h2>',re.S)
name = re.search(name_pattern,html).group(1).strip() if re.search(name_pattern,html) else None
categories_pattern = re.compile('class="el-button cat.*? <span>(.*?)</span>',re.S)
categories = re.findall(categories_pattern,html) if re.search(categories_pattern,html) else None
time_pattern = re.compile('(\d{4}-\d{2}-\d{2}) 上映')
time = re.search(time_pattern,html).group(1) if re.search(time_pattern,html) else None
score_pattern = re.compile('class="score.*?m">(.*?)</p>',re.S)
score = re.search(score_pattern,html).group(1).strip() if re.search(score_pattern,html) else None
drama_pattern = re.compile('<p data-v-63864230="">(.*?)</p>',re.S)
drama = re.search(drama_pattern,html).group(1).strip() if re.search(drama_pattern,html) else None
return {'img': img,
'name': name,
'categories': categories,
'time': time,
'score': score,
'drama': drama
}
接下来在将返回下来的数据请求存入到本地文件夹之中,先确定一个目标文件地址,之后通过os模块检查是否存在这个文件,若不存在则新建一个
result_dir = 'your taget dir'
exists(result_dir) or makedirs(result_dir)
再将数据存入,data_path为我们要存入的文件地址,json.dump()则是我们想以什么样的方式存入数据。
def sava_data(data):
name = data.get('name')
data_path = f'{result_dir}/{name}.json'
json.dump(data,open(data_path,'w',encoding='utf-8'),
ensure_ascii=False,indent=2)
至此我们就完成了本次网站的数据解析。
接下来是完整代码:
import json
import requests, re
import multiprocessing
from urllib.parse import urljoin
from os import makedirs
from os.path import exists
result_dir = 'D:\桌面/movie'
exists(result_dir) or makedirs(result_dir)
base_url = 'https://ssr1.scrape.center/'
total_page = 10
def scrape_page(url):
try:
response = requests.get(url)
if response.status_code == 200:
return response.text
except:
raise
def scrape_index(page):
page = str(page)
index_url = base_url+"page/" + page
return scrape_page(index_url)
def parse_index(html):
detail_url = re.findall(r'<a data-v-7f856186="" href="(.*?)" class', html, re.S)
for item in detail_url:
new_url = urljoin(base_url,item)
yield new_url
def scrapy_detail(url):
return scrape_page(url)
def parse_detail(html):
img_pattern = re.compile('class="item.*?src="(.*?)".*?class="cover">',re.S)
img = re.search(img_pattern,html).group(1) if re.search(img_pattern,html) else None
name_pattern = re.compile('<h2 data-v-63.*?>(.*?)</h2>',re.S)
name = re.search(name_pattern,html).group(1).strip() if re.search(name_pattern,html) else None
categories_pattern = re.compile('class="el-button cat.*? <span>(.*?)</span>',re.S)
categories = re.findall(categories_pattern,html) if re.search(categories_pattern,html) else None
time_pattern = re.compile('(\d{4}-\d{2}-\d{2}) 上映')
time = re.search(time_pattern,html).group(1) if re.search(time_pattern,html) else None
score_pattern = re.compile('class="score.*?m">(.*?)</p>',re.S)
score = re.search(score_pattern,html).group(1).strip() if re.search(score_pattern,html) else None
drama_pattern = re.compile('<p data-v-63864230="">(.*?)</p>',re.S)
drama = re.search(drama_pattern,html).group(1).strip() if re.search(drama_pattern,html) else None
return {'img': img,
'name': name,
'categories': categories,
'time': time,
'score': score,
'drama': drama
}
def sava_data(data):
name = data.get('name')
data_path = f'{result_dir}/{name}.json'
json.dump(data,open(data_path,'w',encoding='utf-8'),
ensure_ascii=False,indent=2)
def main():
for page in range(1,total_page + 1):
index_html = scrape_index(page)
deatil_urls = parse_index(index_html)
for detail_url in deatil_urls:
print(detail_url)
detail_html = scrapy_detail(detail_url)
data = parse_detail(detail_html)
sava_data(data)
if __name__ == '__main__':
main()
也有小伙伴反应爬取速度太慢怎么办,那么此刻加入一个多进程爬取就可以大大提升速度。将main函数改为muti_main() 同时启动也修改一下即刻。我试了一下,不采用多进程完成数据大概要45s,开启多进程仅需13s(当然跟网速也有很大的关系)。
def muti_main(page):
index_html = scrape_index(page)
deatil_urls = parse_index(index_html)
for detail_url in deatil_urls:
detail_html = scrapy_detail(detail_url)
data = parse_detail(detail_html)
sava_data(data)
if __name__ == '__main__':
pool = multiprocessing.Pool()
pages = range(1,total_page + 1)
pool.map(muti_main,pages)
pool.close()
pool.join()
爬取结果如下:
至此我们就完成了一个入门基本的全站爬虫案例,接下来还会有更难的案例,让我们一起进步吧~