爬取猫眼Top100

这是教材上的一个实例,今天学的总结一下。

首先感谢一下同老师送滴书哼

顺便推一下这本书:《Python3网路爬虫开发实战》(崔庆才)

先给代码

Pycharm + py3.7 调过

不很长50行左右,爬一下猫眼top100的一些信息

from builtins import len, open, str, range
import json
import time
from requests.exceptions import RequestException
import requests
import re

def get_one_page(url):
    try:
        # 伪装请求头改为Chrome
        headers = {
            'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko) '
                          'Chome/65.0.3325.162 Safari/537.36'
        }

        response = requests.get(url, headers=headers)
        if response.status_code == 200:
            return response.text
        return None
    except RequestException:
        return None


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

def write_to_file(content):
    with open('result_maoyan.txt', 'a', encoding='utf-8') as f:
        f.write(json.dumps(content, ensure_ascii=False) + '\n')


def main(offset):
    url = 'https://maoyan.com/board/4?offset=' + str(offset)
    html = get_one_page(url)
    for item in parse_one_page(html):
        print (item)
        write_to_file(item)


if __name__ == '__main__':
    for i in range(10):
        main(offset = i*10)
        time.sleep(1)

详解

首先是抓取单页请求信息,一些内容直接码在代码里了

def get_one_page(url):
    try:
        # 伪装请求头改为Chrome, 配置头信息
        # 猫眼有反爬,如果被识别为爬虫会给你返回个大嘴巴子,这里伪装Chrome浏览器
        headers = {
            'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko) '
                          'Chome/65.0.3325.162 Safari/537.36'
        }
		# 使用requests方法
        response = requests.get(url, headers=headers)
        # 通过状态码判断是否出现问题
        if response.status_code == 200:
            # 如果没有问题就返回抓取的页面信息
            return response.text
        return None
    except RequestException:		 # 我想良好的代码风格应该少不了try-expect
        return None

第二部分主要是通过正则表达式提取有价值信息,主要就是正则表达式的使用

有部分涉及到 yield 的使用,贴一篇前辈的文章,关于 yield 讲的比较清楚

def parse_one_page(html):
    pattern = re.compile(
        '<dd>.*?board-index.*?>(.*?)</i>.*?data-src="(.*?)".*?name.*?a.*?>(.*?)</a>.*?star.*?>(.*?)</p>.*?releasetime.*?>(.*?)</p>' 
        '.*?integer.*?>(.*?)</i>.*?fraction.*?>(.*?)</i>.*?</dd>', re.S
    )
    # re.compile()是把字符串转化成正则表达式常用的方法,之后使用findall方法
    items = re.findall(pattern, html)
    for item in items:
        # yield 是我第一次用,就类似于特殊的return,返回设定的字典数据类型
        yield {
            'index': item[0],
            'image': item[1],
            'title': item[2],
            'actor': item[3].strip()[3:],
            'time': item[4].strip()[5:],
            'score': item[5] + item[6]
        }

关于正则表达式,我也是好久才明白,其实匹配的就是 (.*?) 里面的东西。我们看下面的正则表达式:

    pattern = re.compile(
        '<dd>.*?board-index.*?>(.*?)</i>.*?data-src="(.*?)".*?name.*?a.*?>(.*?)</a>.*?star.*?>(.*?)</p>.*?releasetime.*?>(.*?)</p>' 
        '.*?integer.*?>(.*?)</i>.*?fraction.*?>(.*?)</i>.*?</dd>', re.S
    )

现来分析一下网页源码:

我们主要提取以下内容:

  • 排名信息
  • 电影图片
  • 电影名称
  • 主演
  • 发布时间
  • 评分

就以排名信息为栗子:

我们所要获取的,就是 1 这个数字,正则表达式如下:

<dd>.*?board-index.*?>(.*?)</i>

这一部分开始于 < dd > 结束于 < /i > 后面的那个 ( .*? ) 就是我们要匹配的内容。

然后我们写入文件

def write_to_file(content):
    with open('result_maoyan.txt', 'a', encoding='utf-8') as f:
        f.write(json.dumps(content, ensure_ascii=False) + '\n')

调用函数是这样的

def main(offset):
    url = 'https://maoyan.com/board/4?offset=' + str(offset)
    html = get_one_page(url)
    for item in parse_one_page(html):
        print (item)
        write_to_file(item)

由于猫眼每页只显示10条信息,我们先看一下URL有什么规律:

第一页:

第二页:

第三页:

懂了吧,offset就是传入的那个最后的数据,之后调用请求获取当页信息的函数,写入文件的函数,就OK了。

主函数

if __name__ == '__main__':
    for i in range(10):
        main(offset = i*10)
        time.sleep(1)

这里用了 time.sleep 方法,如果我们访问时间过快,会被判定为非正常访问就会被封 IP 不能再继续爬取,这里设定间隔 1 s。

总结

几个关键点:

  1. 请求头处理。

    一般来讲,现在许多网站都有反爬措施,如果检测请求头,发现是来自爬虫,那么多半会拒绝你的访问,所以这里修改了请求头。

  2. 正则表达式。

    这个还是要多练多去看别人是怎么写的。

  3. 请求时间。

    不要过快就好,模仿人类速度。

要开始学Go了,后面的项目有涉及到区块链,有时间更一篇区块链的吧。还有非自然死亡真的太好看了8也!!!

Licensed under CC BY-NC-SA 4.0
自认为是幻象波普星的来客
Built with Hugo
主题 StackJimmy 设计