基于requests和(正则/Xpath)的猫眼电影数据定向爬虫

一.需求分析
应用requests库和正则表达式抓取猫眼电影TOP100的电影名称,时间,评分,图片等信息。
基于requests和(正则/Xpath)的猫眼电影数据定向爬虫_第1张图片项目分析:
1.明确采集网址
猫眼电影榜单TOP100
2.爬取,requests数据采集库,正则表达式数据解析库
3.存,json格式存储到文件

二.分步骤爬取
1.导入需要的包

import codecs
import json
import re
import time
import requests
from colorama import Fore
from fake_useragent import UserAgent
from requests import HTTPError

2.获取页面

def download_page(url, parmas=None):
    """
    根据url地址下载html页面
    :param url:
    :param parmas:
    :return: str
    """
    try:
        ua = UserAgent()
        headers = {
            'User-Agent': ua.random,
            'Host': 'maoyan.com',
            'Cookie': '__mta=216365737.1586537270106.1586587968494.1586587974745.28; uuid_n_v=v1; uuid=FDFCF0307B4A11EA81A9FDE94F2697E46AE0BB693A874A189C91F0B6F3298114; Hm_lvt_703e94591e87be68cc8da0da7cbd0be2=1586537263,1586587448; mojo-uuid=290ecc97cc9252d9e67fddc2fdfba5ff; _lxsdk_cuid=17164fd7ca334-0cfe278836c8a7-4c302f7e-e1000-17164fd7cabc8; _lxsdk=FDFCF0307B4A11EA81A9FDE94F2697E46AE0BB693A874A189C91F0B6F3298114; __mta=216365737.1586537270106.1586575636717.1586587450776.15; _csrf=475c87b2782054e49dc109b59dc40641530b6b61ce9e007ba437dd7fc375b344; _lxsdk_s=17167f7d0b2-36e-60f-f57%7C%7C53; mojo-trace-id=46; mojo-session-id={"id":"fc93bad8aa704378a2e0ae28dfb31398","time":1586587226413}; Hm_lpvt_703e94591e87be68cc8da0da7cbd0be2=1586587975; _lx_utm=utm_source%3DBaidu%26utm_medium%3Dorganic'
        }
        # 请求https协议的时候, 回遇到报错: SSLError
        # verify=Flase不验证证书
        response = requests.get(url, params=parmas, headers=headers)
    except  HTTPError as e:
        print(Fore.RED + '[-] 爬取网站%s失败: %s' % (url, str(e)))
        return None
    else:
        # content返回的是bytes类型, text返回字符串类型
        return response.text

if __name__ == '__main__':
    url = 'https://maoyan.com/board/4'
    html = download_page(url)
    print(html)

在headers中我们设置’Host’与’Cookie’信息,最终response.text返回字符串类型,返回运行结果
基于requests和(正则/Xpath)的猫眼电影数据定向爬虫_第2张图片
可以看到一部分的返回结果,我们需要的信息都在返回的html字符串中。

3.用正则表达式解析html
(1)设置正则表达式

#以
开头,()代表分组,.*?表示任意字符 pattern = re.compile( '
' + '.*?(\d+)' # 获取电影的排名1 + '.*?(.*?) # 获取图片网址和图片名称我和我的祖国 + '.*?

(.*?)

'
# 获取电影的主演:

主演:黄渤,张译,韩昊霖

+ '.*?

(.*?)

'
# 获取电影的上映时间:

上映时间:2019-09-30

'.*?
'
, re.S )

(2)解析的具体代码

def download_page(url, parmas=None):	
	pass
    #此处自行添加获取页面代码

def parse_html(html):
    """
    通过正则表达式对html解析获取电影名称、时间、评分、图片等信息。
    :param html:
    :return:
    """
    pattern = re.compile(
        '
' + '.*?(\d+)' # 获取电影的排名1 + '.*?(.*?) # 获取图片网址和图片名称我和我的祖国 + '.*?

(.*?)

'
# 获取电影的主演:

主演:黄渤,张译,韩昊霖

+ '.*?

(.*?)

'
# 获取电影的上映时间:

上映时间:2019-09-30

'.*?
'
, re.S ) # findall返回列表, finditer返回的是迭代器 #注意:使用findall无法使用item.groups,因为findall返回的不是一个对象 items = re.finditer(pattern, html) print(items) for item in items: print('*'*10) yield { 'index': item.groups()[0], 'image': item.groups()[1], 'title': item.groups()[2], 'star': item.groups()[3].strip().lstrip('主演:'), 'releasetime': item.groups()[4].lstrip('上映时间:') } if __name__ == '__main__': url = 'https://maoyan.com/board/4' html = download_page(url) #print(html) items =parse_html(html) for item in items: print(item)

此处使用yield方法,函数返回一个迭代器,整体返回结果如图所示
基于requests和(正则/Xpath)的猫眼电影数据定向爬虫_第3张图片
3.写入json文件
上一步我们得到的是字典类型的数据,如何将字典类型的数据存入json文件
使用:json.dumps(),具体代码如下:

此处自行添加爬取和解析代码

def save_to_json(data, filename):
    """将爬取的数据信息写入json文件中"""
    # r, r+, w, w+, a, a+
    # 解决的问题:
    #       1. python数据类型如何存储到文件中? json将python数据类型序列化为json字符串
    #       2. json中中文不能存储如何解决?     ensure_ascii=False
    #       3. 存储到文件中的数据不是utf-8格式的,怎么解决?   ''.encode('utf-8')
    # with open(filename, 'ab')  as f:
    #     f.write(json.dumps(data, ensure_ascii=False,indent=4).encode('utf-8'))
    #     print(Fore.GREEN + '[+] 保存电影 %s 的信息成功' %(data['title']))

    with codecs.open(filename, 'a', 'utf-8') as f:
        # f.write(json.dumps(data, ensure_ascii=False) + '\n')
        #json.dumps将python字典型数据转化为json格式
        f.write(json.dumps(data, ensure_ascii=False, indent=4))
        print(Fore.GREEN + '[+] 保存电影 %s 的信息成功' % (data['title']))

if __name__ == '__main__':
    url = 'https://maoyan.com/board/4'
    html = download_page(url)
    #print(html)
    items =parse_html(html)
    for item in items:
        save_to_json(item)

结果如图:

三.爬取所有的top100
上述操作只是爬取了top100页面的第一页也就是前10部电影,我们要爬取剩余9页每一页的电影。
第二页的网址如下:

https://maoyan.com/board/4?offset=10

第三页的网址如下:

https://maoyan.com/board/4?offset=20

我们发现改变参数?offset=就可以改变页数
我们定义一个函数,表示爬取一页的,通过for循环我们让其爬取所有的10页,最终的完整代码如下:

#coding:utf-8
#date:2020/4/1216:07
#author:CQ_Liu
import codecs
import json
import re
import time

import urllib3

import requests
from colorama import Fore
from fake_useragent import UserAgent
from requests import HTTPError

def download_page(url, parmas=None):
    """
    根据url地址下载html页面
    :param url:
    :param parmas:
    :return: str
    """
    try:
        ua = UserAgent()
        headers = {
            'User-Agent': ua.random,
            'Host': 'maoyan.com',
            'Cookie': '__mta=216365737.1586537270106.1586587968494.1586587974745.28; uuid_n_v=v1; uuid=FDFCF0307B4A11EA81A9FDE94F2697E46AE0BB693A874A189C91F0B6F3298114; Hm_lvt_703e94591e87be68cc8da0da7cbd0be2=1586537263,1586587448; mojo-uuid=290ecc97cc9252d9e67fddc2fdfba5ff; _lxsdk_cuid=17164fd7ca334-0cfe278836c8a7-4c302f7e-e1000-17164fd7cabc8; _lxsdk=FDFCF0307B4A11EA81A9FDE94F2697E46AE0BB693A874A189C91F0B6F3298114; __mta=216365737.1586537270106.1586575636717.1586587450776.15; _csrf=475c87b2782054e49dc109b59dc40641530b6b61ce9e007ba437dd7fc375b344; _lxsdk_s=17167f7d0b2-36e-60f-f57%7C%7C53; mojo-trace-id=46; mojo-session-id={"id":"fc93bad8aa704378a2e0ae28dfb31398","time":1586587226413}; Hm_lpvt_703e94591e87be68cc8da0da7cbd0be2=1586587975; _lx_utm=utm_source%3DBaidu%26utm_medium%3Dorganic'
        }
        # 请求https协议的时候, 回遇到报错: SSLError
        # verify=Flase不验证证书
        #requests.packages.urllib3.disable_warnings()
        response = requests.get(url, params=parmas, headers=headers)
    except  HTTPError as e:
        print(Fore.RED + '[-] 爬取网站%s失败: %s' % (url, str(e)))
        return None
    else:
        # content返回的是bytes类型, text返回字符串类型
        return response.text

def parse_html(html):
    """
    通过正则表达式对html解析获取电影名称、时间、评分、图片等信息。
    :param html:
    :return:
    """
    pattern = re.compile(
        '
' + '.*?(\d+)' # 获取电影的排名1 + '.*?(.*?) # 获取图片网址和图片名称我和我的祖国 + '.*?

(.*?)

'
# 获取电影的主演:

主演:黄渤,张译,韩昊霖

+ '.*?

(.*?)

'
# 获取电影的上映时间:

上映时间:2019-09-30

'.*?
'
, re.S ) # findall返回列表, finditer返回的是迭代器 #注意:使用findal无法使用item.groups,因为返回的不是一个对象 items = re.finditer(pattern, html) for item in items: print(item.groups()) print('*'*10) yield { 'index': item.groups()[0], 'image': item.groups()[1], 'title': item.groups()[2], 'star': item.groups()[3].strip().lstrip('主演:'), 'releasetime': item.groups()[4].lstrip('上映时间:') } def save_to_json(data, filename): """将爬取的数据信息写入json文件中""" # r, r+, w, w+, a, a+ # 解决的问题: # 1. python数据类型如何存储到文件中? json将python数据类型序列化为json字符串 # 2. json中中文不能存储如何解决? ensure_ascii=False # 3. 存储到文件中的数据不是utf-8格式的,怎么解决? ''.encode('utf-8') # with open(filename, 'ab') as f: # f.write(json.dumps(data, ensure_ascii=False,indent=4).encode('utf-8')) # print(Fore.GREEN + '[+] 保存电影 %s 的信息成功' %(data['title'])) with codecs.open(filename, 'a', 'utf-8') as f: # f.write(json.dumps(data, ensure_ascii=False) + '\n') #json.dumps将python字典型数据转化为json格式 f.write(json.dumps(data, ensure_ascii=False, indent=4)) print(Fore.GREEN + '[+] 保存电影 %s 的信息成功' % (data['title'])) def get_one_page(page=1): # url = 'https://maoyan.com/board/' # 采集热映口碑榜, 只有一页。 # 采集电影TOP100, 总共10页. url的规则: https://maoyan.com/board/4?offset=(page-1)*10 url = 'https://maoyan.com/board/4?offset=%s' % ((page - 1) * 10) html = download_page(url) # print(html) items = parse_html(html) # item是字典 for item in items: save_to_json(item, 'maoyan.json') if __name__ == '__main__': for page in range(1, 11): get_one_page(page) print(Fore.GREEN + '[+] 采集第[%s]页数据' % (page)) # 反爬虫策略: 方式爬虫速度太快被限速, 在采集数据的过程中,休眠一段时间 time.sleep(0.5)

运行结果如下(由于反爬虫限制,此处只粘贴爬取第一页的结果):
基于requests和(正则/Xpath)的猫眼电影数据定向爬虫_第4张图片

四.使用xpath解析,更改解析函数如下:

def parse_html(html):
    """
    通过Xpath对html解析获取电影名称、时间、评分、图片等信息。
    :param html:
    :return:
    """
    # 1). 将传入的html文档内容通过lxml解析器进行解析
    html = etree.HTML(html)
    # 2). 通过Xpath语法获取电影的信息
    # //dl[@class="board-wrapper"]/dd, 从当前节点寻找class属性名等于board-wrapper的dl标签, 拿出里面的所有dd标签
    movies = html.xpath('//dl[@class="board-wrapper"]/dd')
    for movie in movies:
        # 从当前dd节点寻找i标签里面的文本内容
        index = movie.xpath('./i/text()')[0]
        # .//从当前标签寻找img标签(class='border-img'), 获取标签的data-src和alt属性
        # /不深入寻找, // 深入寻找
        image = movie.xpath('./a/img[@class="board-img"]/@data-src')[0]
        title = movie.xpath('./a/img[@class="board-img"]/@alt')[0]
        star = movie.xpath('.//p[@class="star"]/text()')[0]
        releasetime = movie.xpath('.//p[@class="releasetime"]/text()')[0]
        yield {
            'index': index,
            'image': image,
            'title': title,
            'star': star.strip().lstrip('主演:'),
            'releasetime': releasetime.lstrip('上映时间:')
        }

你可能感兴趣的:(python)