Python爬虫(三):爬取猫眼电影网经典电影TOP100信息并存入本地Markdown文件(上)


运行环境:Python3.6.2Pycharm2017.2
附此爬虫代码GitHub地址:https://github.com/IMWoolei/MaoYanMovies

==>【效果链接


正文

分析

需要获取的信息

进入到猫眼网经典电影TOP100页面【链接
图片
需要抓取的数据有名次,海报,影片名、主演、上映时间以及评分。

网页信息分析

page
从中可以看到,每一步影片的信息都分别存在于<dd></dd>标签中。
所以只需要使用正则匹配出<dd></dd>标签中我们需要的数据即可。
正则表达式可以写成如下表达式

import re
pattern = re.compile(
        '<dd>.*?<i class="board-index.*?>(\d+)</i>.*?<img data-src="(.*?)".*?<p class="name">'
        '<a.*?>(.*?)</a>.*?<p class="star">(.*?)</p>.*?'
        '<p class="releasetime">(.*?)</p>.*?<i class="integer">(.*?)</i><i class="fraction">(.*?)</i>.*?</dd>',
        re.S)
# ① (\d+):匹配一个或多个数字
# ② 第一个(.*?):匹配电影海报图片地址
# ③ 第二个(.*?):匹配电影名
# ④ 第三个(.*?):匹配电影主演
# ⑤ 第四个和第五个(.*?):匹配电影评分

代码

(一)将获取到的电影信息写入文本文档中

需要注意的是我们获取到的影片信息JSON数据格式是无法直接写入文本的,所以我们需要先编码成str类型才能够进行写入。

Python3 中可以使用json模块来对JSON数据进行编解码,它包含了两个函数:
- json.dumps(): 对数据进行编码。
- json.loads(): 对数据进行解码。

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 2017/11/25 15:08 
# @File : MaoYan_TOP100.py 
# @Software: PyCharm

import requests
import re
import json

headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36',
    'Referer': 'http://maoyan.com/board/4?offset=0'}


# 获取请求页面
def getPage(url):
    try:
        response = requests.get(url, headers=headers)
        # print(response.status_code)
        if response.status_code == 200:
            return response.text
        else:
            return None
    except Exception:
        return None


# 获取电影信息
def getInfo(html):
    # 正则匹配出电影的索引、海报、电影名、主演、评分
    pattern = re.compile(
        '<dd>.*?<i class="board-index.*?>(\d+)</i>.*?<img data-src="(.*?)".*?<p class="name">'
        '<a.*?>(.*?)</a>.*?<p class="star">(.*?)</p>.*?'
        '<p class="releasetime">(.*?)</p>.*?<i class="integer">(.*?)</i><i class="fraction">(.*?)</i>.*?</dd>',
        re.S)

    items_list = re.findall(pattern, html)
    for item in items_list:
        yield {
            'index': item[0],  # 索引
            'image': item[1],  # 海报
            'name': item[2],  # 电影名
            'actor': item[3].strip()[3:],  # 主演
            'time': item[4].strip()[5:],  # 上映时间
            'score': item[5] + item[6]  # 评分
        }


# 采用这种方法写入数据耦合性高
# def writeData(content):
#     fout = open('Movies_Info.txt', mode='a', encoding='utf-8')
#     for item in content:
#         fout.write(json.dumps(item, ensure_ascii=False) + '\n')
#         fout.write('---------------------------\n')
#     fout.close()

# 写入文件中
def writeData(field):
    with open('Movies_Info.txt', 'a', encoding='utf-8') as f:
        f.write(json.dumps(field, ensure_ascii=False) + '\n')  # json.dumps 用于将 Python 对象编码成 JSON 字符串,若对象为字符串是无法写入文本的
        f.close()


if __name__ == '__main__':
    for num in [i * 10 for i in range(11)]:
        url = 'http://maoyan.com/board/4?offset=' + str(num)
        html = getPage(url)
        for item in getInfo(html):
            print(item)
            writeData(item)

运行结果

图片

(二)多进程爬取数据

Python3标准库中的multiprocessing模块提供了Pool类,用于提供指定数量的进程给用户使用,当有新的请求提交到Pool中时,如果池还没有满,就会创建一个新的进程来执行请求。如果池满,请求就会告知先等待,直到池中有进程结束,才会创建新的进程来执行这些请求。

import requests
import re
import json
from multiprocessing import Pool

headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36'}


def getPage(url):
    response = requests.get(url, headers=headers)
    print(response.status_code)
    if response.status_code == 200:
        return response.text
    else:
        return None


def getInfo(html):
    pattern = re.compile(
        '<dd>.*?<i class="board-index.*?>(\d+)</i>.*?<img data-src="(.*?)".*?<p class="name">'
        '<a.*?>(.*?)</a>.*?<p class="star">(.*?)</p>.*?'
        '<p class="releasetime">(.*?)</p>.*?<i class="integer">(.*?)</i><i class="fraction">(.*?)</i>.*?</dd>',
        re.S)
    items_list = re.findall(pattern, html)
    for item in items_list:
        yield {
            'index': item[0],
            'image': item[1],
            'name': item[2],
            'actor': item[3].strip()[3:],
            'time': item[4].strip()[5:],
            'score': item[5] + item[6]
        }


def writeData(field):
    with open('Movies_Info_MP.txt', 'a', encoding='utf-8') as f:
        f.write(json.dumps(field, ensure_ascii=False) + '\n')
        f.close()


def main(num):
    url = 'http://maoyan.com/board/4?offset=' + str(num)
    html = getPage(url)
    for item in getInfo(html):
        print(item)
        writeData(item)


if __name__ == '__main__':
    pool = Pool()
    pool.map(main, [i * 10 for i in range(10)])  # 与内置的map函数用法行为基本一致,它会使进程阻塞直到返回结果。
    pool.close()  # 关闭进程池(pool),使其不在接受新的任务
    pool.join()  # 调用join之前,先调用close函数,否则会出错。执行完close后不会有新的进程加入到pool,join函数等待所有子进程结束

运行结果
多线程
多进程爬取数据可以提高效率,但是因为多进程的原因,多进程的写入会使写入顺序不一致,虽然字典的索引不会影响数据的取用,但是如果想要对字典进行排序的话,可以参考如下代码:

# 示例字典列表
stus = [
    {"name":"zhangsan", "age":18}, 
    {"name":"lisi", "age":19},      
    {"name":"wangwu", "age":17} ]


# 按name排序:
>>> stus.sort(key = lambda x:x['name'])
>>> stus
[{'age': 19, 'name': 'lisi'}, {'age': 17, 'name': 'wangwu'}, {'age': 18, 'name': 'zhangsan'}]

# 按age排序:
>>> stus.sort(key = lambda x:x['age'])
>>> stus
[{'age': 17, 'name': 'wangwu'}, {'age': 18, 'name': 'zhangsan'}, {'age': 19, 'name': 'lisi'}]

  • 0
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值