Боевой проект
Битва со статической веб-страницей
В этом разделе мы покажем вам общий процесс полного поискового робота. Содержание этого проекта состоит в том, чтобы извлечь всю информацию о фильмах из списка Maoyan Movie TOP100 и сохранить ее в файле CSV. Адрес домашней страницы: http:// maoyan.com/board/ 4. В 3.2.2 мы получили все названия фильмов на первой странице, но как получить данные второй и третьей страницы, то есть получить URL, соответствующий второй и третьи страницы, то мы можем продолжать листать страницы в браузере, чтобы найти изменяющийся закон URL-адреса в адресной строке:
第二页: http://maoyan.com/board/4?offset=10
第三页: http://maoyan.com/board/4?offset=20
第四页: http://maoyan.com/board/4?offset=30
......
Мы видим, что правило изменения URL заключается в том, что значение смещения параметра постоянно смещается, а значение смещения каждой страницы равно 10, поэтому мы можем написать функцию для получения данных каждой страницы, а полученный параметр — это номер страницы. :
import requests
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36'
}
# 偏移参数,默认为0,即为第一页
params = {
'offset': 0
}
def get_html(page):
'''
获取一页html页面
:param page: 页数
:return: 该页html页面
'''
params['offset'] = page * 10
url = 'http://maoyan.com/board/4'
try:
response = requests.get(url, headers=headers, params=params)
if response.status_code == 200:
html = response.text
return html
else:
return -1
except:
return None
Когда мы получим html-страницу, мы можем извлечь соответствующую информацию о фильме, такую как атрибуты, которые будет иметь каждый фильм в списке: название фильма, главная роль, время выпуска, рейтинг и другую информацию. Есть много способов извлечь информацию.Давайте воспользуемся регулярными выражениями для извлечения информации о фильме:
def parse_infor(html):
'''
提取html页面中的电影信息
:param html: html页面
:return: 电影信息列表
'''
# 编写正则字符串规则,提取 电影名,主演,上映时间,评分信息
pat = re.compile('<div class="movie-item-info">.*?<p.*?><a.*?>(.*?)</a></p>.*?<p.*?>(.*?)</p>.*?<p.*?>(.*?)</p>.*?</div>.*?<div.*?>.*?<p.*?><i.*?>(.*?)</i><i.*?>(.*?)</i></p>.*?</div>.*?</div>.*?</div>', re.S)
# 得到一个二重列表
results = re.findall(pat, html)
one_page_film = []
if results:
for result in results:
film_dict = {}
# 获取电影名信息
film_dict['name'] = result[0]
# 获取主演信息
start = result[1]
# 替换字符串中的 '\n' 字符,即换行字符
start.replace('\n', '')
# 去掉字符串两边的空格,并使用切片去除字符串开头的'主演:'三个字符
start = start.strip()[3:]
film_dict['start'] = start
# 获取上映时间信息
releasetime = result[2]
# 使用切片去除字符串开头的'上映时间:'五个字符
releasetime = releasetime[5:]
film_dict['releasetime'] = releasetime
# 获取评分信息,由于评分是有两个字符拼接的,这里我们提取后也需要进行拼接操作
left_half =result[3]
right_half = result[4]
score = left_half + right_half
film_dict['score'] = score
# 打印该电影信息:
print(film_dict)
# 将该电影信息字典存入一页电影列表中
one_page_film.append(film_dict)
return one_page_film
else:
return None
Читатели, которые не знакомы с регулярными выражениями, должны просмотреть предыдущие знания. Хотя обычное написание может быть проблематичным, его эффективность извлечения в то время была самой высокой. Далее мы можем сохранить извлеченную информацию о фильме. Здесь мы сохраняем ее как документ CSV:
def save_infor(one_page_film):
'''
存储提取好的电影信息
:param html: 电影信息列表
:return: None
'''
with open('top_film.csv', 'a', newline='') as f:
csv_file = csv.writer(f)
for one in one_page_film:
csv_file.writerow([one['name'], one['start'], one['releasetime'], one['score']])
Выше описан процесс получения HTML-страницы, извлечения информации о фильме и сохранения ее в формате CSV. Далее мы создаем десять страниц URL-адресов, чтобы завершить сбор и хранение всей информации о фильмах из списка Maoyan Movie TOP100. Ниже приведен полный программа:
import requests
import re
import csv
import time
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36'
}
params = {
'offset': 0
}
def get_html(page):
'''
获取一页html页面
:param page: 页数
:return: 该页html页面
'''
params['offset'] = page * 10
url = 'http://maoyan.com/board/4'
try:
response = requests.get(url, headers=headers, params=params)
if response.status_code == 200:
html = response.text
return html
else:
return -1
except:
return None
def parse_infor(html):
'''
提取html页面中的电影信息
:param html: html页面
:return: 电影信息列表
'''
pat = re.compile('<div class="movie-item-info">.*?<p.*?><a.*?>(.*?)</a></p>.*?<p.*?>(.*?)</p>.*?<p.*?>(.*?)</p>.*?</div>.*?<div.*?>.*?<p.*?><i.*?>(.*?)</i><i.*?>(.*?)</i></p>.*?</div>.*?</div>.*?</div>', re.S)
results = re.findall(pat, html)
one_page_film = []
if results:
for result in results:
film_dict = {}
# 获取电影名信息
film_dict['name'] = result[0]
# 获取主演信息
start = result[1]
# 替换字符串中的 '\n' 字符,即换行字符
start.replace('\n', '')
# 去掉字符串两边的空格,并使用切片去除字符串开头的'主演:'三个字符
start = start.strip()[3:]
film_dict['start'] = start
# 获取上映时间信息
releasetime = result[2]
# 使用切片去除字符串开头的'上映时间:'五个字符
releasetime = releasetime[5:]
film_dict['releasetime'] = releasetime
# 获取评分信息
left_half =result[3]
right_half = result[4]
score = left_half + right_half
film_dict['score'] = score
# 打印该电影信息:
print(film_dict)
# 将该电影信息字典存入一页电影列表中
one_page_film.append(film_dict)
return one_page_film
else:
return None
def save_infor(one_page_film):
'''
存储提取好的电影信息
:param one_page_film: 电影信息列表
:return: None
'''
with open('top_film.csv', 'a', newline='', errors='ignore') as f:
csv_file = csv.writer(f)
for one in one_page_film:
csv_file.writerow([one['name'], one['start'], one['releasetime'], one['score']])
if __name__ == "__main__":
# 利用循环构建页码
for page in range(10):
# 请求页面
html = get_html(page)
if html:
# 提取信息
one_page_film = parse_infor(html)
if one_page_film:
# 存储信息
save_infor(one_page_film)
time.sleep(1)
Динамический бой на веб-странице
В этом разделе мы просканируем данные о кассовых сборах фильмов Маоянь в реальном времени и научимся получать нужные данные на динамических веб-страницах.Maoyan Pro - Кассовые сборы в реальном времени, его веб-сайт: https://piaofang.maoyan.com/dashboard, а затем мы можем видеть текущие данные о кассовых сборах фильмов в реальном времени, и мы можем видеть, что данные «Сегодня в реальном времени» постоянно динамично растут. :
Однако, когда мы смотрим на исходный код веб-страницы, там нет информации о кассовых сборах, связанных с фильмом, поэтому можно сделать вывод, что страница может использовать Ajax (т.е. «Асинхронный Javascript и XML» (асинхронный JavaScript и XML)) технология, а именно динамическая веб-страница (это относится к технологии веб-программирования, относящейся к статическим веб-страницам. Для статических веб-страниц с генерацией HTML-кода содержимое и эффект отображения страницы в основном не изменятся - если вы не измените код страницы Динамические веб-страницы не являются. Хотя код страницы не изменился, отображаемый контент может меняться со временем, окружающей средой или результатом операций с базой данных). Мы можем использовать инструменты разработчика браузера для анализа:
Мы можем обнаружить, что время от времени будет поступать новый запрос, тип запроса — xhr, а тип запроса Ajax — xhr.Этот запрос может быть информацией о кассах, обновляемой в режиме реального времени, и находиться в этих файлах. , поэтому для анализа выбираем один:
В предварительном просмотре мы можем видеть много информации, связанной с фильмом, то есть данные о кассовых сборах фильма в реальном времени, которые мы хотим получить, и это содержимое находится в формате JSON, который автоматически анализируется инструментами разработчика браузера для просмотра. , Затем нам нужно только использовать Python для имитации этих запросов Ajax, получить данные и затем проанализировать их, и эти Ajax по-прежнему являются HTTP-запросами, поэтому, пока вы получаете соответствующий URL-адрес и используете Python для имитации запроса, мы можно скопировать его напрямую, как показано ниже:
Получите ссылку на запрос, а затем мы используем Python для имитации запроса:
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36'
}
def get_html():
'''
获取JSON文件
:return: JSON格式的数据
'''
# 请求second.json的URL
url = 'https://box.maoyan.com/promovie/api/box/second.json'
try:
response = requests.get(url, headers=headers)
if response.status_code == 200:
# 由于是JSON文件,我们可以返回JSON格式的数据便于后续提取
return response.json()
else:
return -1
except:
return None
Получив соответствующие данные JSON, мы можем использовать их для извлечения.
def parse_infor(json):
'''
从JSON数据中提取电影票房数据,包括:电影名,上映信息,综合票房,票房占比,累计票房
:param json: JSON格式的数据
:return: 每次循环返回一次字典类型的电影数据
'''
if json:
# 利用json中的get()方法层层获取对应的信息
items = json.get('data').get('list')
for item in items:
piaofang = {}
piaofang['电影名'] = item.get('movieName')
piaofang['上映信息'] = item.get('releaseInfo')
piaofang['综合票房'] = item.get('boxInfo')
piaofang['票房占比'] = item.get('boxRate')
piaofang['累计票房'] = item.get('sumBoxInfo')
# 利用生成器每次循环都返回一个数据
yield piaofang
else:
return None
Читатели могут заметить, что мы не используем обычный возврат для возврата функции, а используем генераторы, чтобы мы могли возвращать данные один раз за цикл, а конкретные читатели могутГенератор | Официальный сайт Ляо СюэфэнаЧтобы узнать больше об обучении, мы сохраним извлеченную информацию о кассовых сборах в виде отформатированного HTML-файла:
def save_infor(results):
'''
存储格式化的电影票房数据HTML文件
:param results: 电影票房数据的生成器
:return: None
'''
rows = ''
for piaofang in results:
# 利用Python中的format字符串填充html表格中的内容
row = '<tr><td>{}</td><td>{}</td><td>{}</td><td>{}</td><td>{}</td></tr>'.format(piaofang['电影名'],
piaofang['上映信息'],
piaofang['综合票房'],
piaofang['票房占比'],
piaofang['累计票房'])
# 利用字符串拼接循环存储每个格式化的电影票房信息
rows = rows + '\n' + row
# 利用字符串拼接处格式化的HTML页面
piaofang_html = '''
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>电影票房</title>
</head>
<body>
<style>
.table1_5 table {
width:100%;
margin:15px 0
}
.table1_5 th {
background-color:#00BFFF;
color:#FFFFFF
}
.table1_5,.table1_5 th,.table1_5 td
{
font-size:0.95em;
text-align:center;
padding:4px;
border:1px solid #dddddd;
border-collapse:collapse
}
.table1_5 tr:nth-child(odd){
background-color:#aae9fe;
}
.table1_5 tr:nth-child(even){
background-color:#fdfdfd;
}
</style>
<table class='table1_5'>
<tr>
<th>电影名</th>
<th>上映信息</th>
<th>综合票房</th>
<th>票房占比</th>
<th>累计票房</th>
</tr>
''' + rows + '''
</table>
</body>
</html>
'''
# 存储已经格式化的html页面
with open('piaofang.html', 'w', encoding='utf-8') as f:
f.write(piaofang_html)
Мы интегрируем описанный выше процесс, чтобы получить полный пример кода сбора данных о кассовых сборах:
import requests
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36'
}
def get_html():
'''
获取JSON文件
:return: JSON格式的数据
'''
# 请求second.json的URL
url = 'https://box.maoyan.com/promovie/api/box/second.json'
try:
response = requests.get(url, headers=headers)
if response.status_code == 200:
# 由于是JSON文件,我们可以返回JSON格式的数据便于后续提取
return response.json()
else:
return -1
except:
return None
def parse_infor(json):
'''
从JSON数据中提取电影票房数据,包括:电影名,上映信息,综合票房,票房占比,累计票房
:param json: JSON格式的数据
:return: 每次循环返回一次字典类型的电影数据
'''
if json:
# 利用json中的get()方法层层获取对应的信息
items = json.get('data').get('list')
for item in items:
piaofang = {}
piaofang['电影名'] = item.get('movieName')
piaofang['上映信息'] = item.get('releaseInfo')
piaofang['综合票房'] = item.get('boxInfo')
piaofang['票房占比'] = item.get('boxRate')
piaofang['累计票房'] = item.get('sumBoxInfo')
# 利用生成器每次循环都返回一个数据
yield piaofang
else:
return None
def save_infor(results):
'''
存储格式化的电影票房数据HTML文件
:param results: 电影票房数据的生成器
:return: None
'''
rows = ''
for piaofang in results:
# 利用Python中的format字符串填充html表格中的内容
row = '<tr><td>{}</td><td>{}</td><td>{}</td><td>{}</td><td>{}</td></tr>'.format(piaofang['电影名'],
piaofang['上映信息'],
piaofang['综合票房'],
piaofang['票房占比'],
piaofang['累计票房'])
# 利用字符串拼接循环存储每个格式化的电影票房信息
rows = rows + '\n' + row
# 利用字符串拼接处格式化的HTML页面
piaofang_html = '''
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>电影票房</title>
</head>
<body>
<style>
.table1_5 table {
width:100%;
margin:15px 0
}
.table1_5 th {
background-color:#00BFFF;
color:#FFFFFF
}
.table1_5,.table1_5 th,.table1_5 td
{
font-size:0.95em;
text-align:center;
padding:4px;
border:1px solid #dddddd;
border-collapse:collapse
}
.table1_5 tr:nth-child(odd){
background-color:#aae9fe;
}
.table1_5 tr:nth-child(even){
background-color:#fdfdfd;
}
</style>
<table class='table1_5'>
<tr>
<th>电影名</th>
<th>上映信息</th>
<th>综合票房</th>
<th>票房占比</th>
<th>累计票房</th>
</tr>
''' + rows + '''
</table>
</body>
</html>
'''
# 存储已经格式化的html页面
with open('piaofang.html', 'w', encoding='utf-8') as f:
f.write(piaofang_html)
if __name__ == "__main__":
# 获取信息
json = get_html()
# 提取信息
results = parse_infor(json)
# 存储信息
save_infor(results)
Эффект хранения файла HTML показан на следующем рисунке:
Видно, что краулер динамических веб-страниц может быть проще, главное найти соответствующий запрос в формате XHR, как правило, файлы в этом формате имеют формат JSON, и извлечение будет относительно проще и удобнее. может спросить: "Почему эта информация должна храниться в формате HTML-файла? Читатели, которым нравятся фильмы, могут часто открывать Maoyan Movies для просмотра данных о ежедневных кассовых сборах фильмов. А как насчет аплета поискового робота, отправленного в личный почтовый ящик, который избавляет нас от открытия веб-страницы?" каждый день и позволяя данным активно служить нам. Это можно рассматривать как учебное приложение. Заинтересованные читатели могут попробовать его для себя. Расширяйте информационные электронные письма о кассовых сборах в реальном времени, получаемые каждый день, регулярно сканируйте и отправляйте их автору каждый день. , содержимое списка показано на следующем рисунке:
Содержание акции показано на следующем рисунке: