'''
## 爬取崔庆才老师的网站,获取电影详情页的地址、片名、类别、封面、评分、剧情
## 最后保存成一个个json文件
'''
from urllib.parse import urljoin
from selenium import webdriver
from selenium.common.exceptions import TimeoutException
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait
import logging
import json
from os import makedirs
from os.path import exists
# 设置无头模式
options = webdriver.ChromeOptions()
options.add_argument('--headless')
logging.basicConfig(level=logging.INFO,
format='%(asctime)s - %(levelname)s: %(message)s')
''' 定义电影列表页的地址变量, 接着定义几个常量:等待秒数、爬取页数、目录结果 '''
INDEX_URL = 'https://spa2.scrape.center/page/{page}'
TIME_OUT = 10
TOTAL_PAGE = 10
RESULTS_DIR = 'results'
# 定义一个模拟浏览器的webdriver对象browser,再设置等待的时间
# browser = webdriver.Chrome()
browser = webdriver.Chrome(options=options)
wait = WebDriverWait(browser, TIME_OUT)
'''
1、定义一个通用的爬取网址的方法, 包含三个参数:
网页地址、页面加载是否成功的条件condition、以及定位器 (元组,定位节点)
'''
def scrape_page(url, condition, locator):
logging.info('爬取的网页地址为%s', url)
try:
browser.get(url)
wait.until(condition(locator))
except TimeoutException:
logging.error('爬取时发生的错误信息为 %s', url, exc_info=True)
'''
2、带入参数, 进一步爬取网址列表页的方法, 调用上面的scrape_page方法
'''
def scrape_index(page):
# 一个url列表页
url = INDEX_URL.format(page=page)
scrape_page(url, condition=EC.visibility_of_all_elements_located,
locator=(By.CSS_SELECTOR, '#index .item'))
'''
3、具体解析列表页内容的方法, 解析并生成详情页的URL并以完整地址返回
'''
def parse_index():
elements = browser.find_elements(By.CSS_SELECTOR, '#index .item .name')
for element in elements:
href = element.get_attribute('href')
# 用urljoin拼接生成一个详情页地址
yield urljoin(INDEX_URL, href)
'''
4、定义一个通用的爬取详情页网页的方法,包含:
详情页地址、页面是否加载成功的condition、以及定位
h2是页面是否加载的标志,成功就出现h2
'''
def scrape_detail(url):
scrape_page(url, condition=EC.visibility_of_element_located,
locator=(By.TAG_NAME, 'h2'))
'''
5、具体解析详情页的方法,包括详情页里面各字段的节点并返回
然后定制地址, 再用了一系列的CSS选择器, 解析各节点内容并返回
'''
def parse_detail():
url = browser.current_url
name = browser.find_element(By.TAG_NAME, 'h2').text
categories = [element.text for element in browser.find_elements(
By.CSS_SELECTOR, '.categories button span')]
cover = browser.find_element(
By.CSS_SELECTOR, '.cover').get_attribute('src')
score = browser.find_element(By.CLASS_NAME, 'score').text
drama = browser.find_element(By.CSS_SELECTOR, '.drama p').text
# 返回内容:地址、片名、类别、封面、评分、剧情
return {
'url': url,
'name': name,
'categories': categories,
'cover': cover,
'score': score,
'drama': drama
}
'''
6、保存方法, 保存详情页解析后的信息为json
'''
exists(RESULTS_DIR) or makedirs(RESULTS_DIR)
def save_data(data):
# data是字典类型,以键取值
name = data.get('name')
# 保存路径
data_path = f'{RESULTS_DIR}/{name}.json'
# 把字典类型数据,转换为json数据
json.dump(data, open(data_path, 'w', encoding='utf-8'),
ensure_ascii=False, indent=2)
''' 7、主运行程序,
把上面方法逐个调用, 从获取列表页到详情页,
再把详情页解析出来, 得到的字段保存'''
if __name__ == '__main__':
try:
for page in range(1, TOTAL_PAGE + 1):
# 爬取一页的电影列表, 共十个
scrape_index(page)
# 解析出每页的详情页地址
detail_urls = parse_index()
# 把详情页汇总为地址列表,再遍历
for detail_url in list(detail_urls):
logging.info('得到详情页地址 %s', detail_url)
scrape_detail(detail_url)
detail_data = parse_detail()
logging.info('详情页地址内容 %s', detail_data)
save_data(detail_data)
finally:
browser.close()
标签:url,selenium,爬虫,detail,案例,详情页,data,page,browser
From: https://blog.51cto.com/u_15930659/6021571