Сбор данных Cat's Eye Movie для Python Crawler Введение (фактический бой)

Python

Боевой проект

Битва со статической веб-страницей

В этом разделе мы покажем вам общий процесс полного поискового робота. Содержание этого проекта состоит в том, чтобы извлечь всю информацию о фильмах из списка 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 для просмотра данных о ежедневных кассовых сборах фильмов. А как насчет аплета поискового робота, отправленного в личный почтовый ящик, который избавляет нас от открытия веб-страницы?" каждый день и позволяя данным активно служить нам. Это можно рассматривать как учебное приложение. Заинтересованные читатели могут попробовать его для себя. Расширяйте информационные электронные письма о кассовых сборах в реальном времени, получаемые каждый день, регулярно сканируйте и отправляйте их автору каждый день. , содержимое списка показано на следующем рисунке:

Содержание акции показано на следующем рисунке: