20201201 2020-2021-2 《Python程序设计》实验4报告

20201201 2020-2021-2 《Python程序设计》实验4报告

 

课程:《Python程序设计》
班级: 202012
姓名: 张敦敏
学号: 20201201
实验教师:王志强
实验日期:2021年5月24日-2021年6月30日
必修/选修: 公选课

 

1.实验内容

  • 学习如何使用网络爬虫技术

  • 通过使用网络爬虫技术实现某一功能

 

2.实验设计

本次实验计划通过爬取猫眼电影排行来实现对爬虫技术的学习实践。

实验主要分为四步:

  1. 观察网页的url与HTML
  2. 分析HTML,写出对应的正则表达式
  3. 调用requests库,爬取HTML,并使用正则表达式提取对应内容
  4. 将提取内容整理写入文件

 

3.实验过程

3.1 观察网页的url与HTML

观察得出:

1.猫眼电影排行每页显示10个排名,每页由offset参数控制,每翻一页offset+10

2.HTML中的每一个排名信息放在<dd></dd>中,由其中的不同的class放置其他不同信息

3.2 分析HTML,写出对应的正则表达式

 爬取一部分HTML,得到代码:

                 <dd>
                        <i class="board-index board-index-2">2</i>
    <a href="/films/1297" title="肖申克的救赎" class="image-link" data-act="boarditem-click" data-val="{movieId:1297}">
      <img src="//s3plus.meituan.net/v1/mss_e2821d7f0cfe4ac1bf9202ecf9590e67/cdn-prod/file:5788b470/image/loading_2.e3d934bf.png" alt="" class="poster-default" />
      <img data-src="https://p0.meituan.net/movie/8112a8345d7f1d807d026282f2371008602126.jpg@160w_220h_1e_1c" alt="肖申克的救赎" class="board-img" />
    </a>
    <div class="board-item-main">
      <div class="board-item-content">
              <div class="movie-item-info">
        <p class="name"><a href="/films/1297" title="肖申克的救赎" data-act="boarditem-click" data-val="{movieId:1297}">肖申克的救赎</a></p>
        <p class="star">
                主演:蒂姆·罗宾斯,摩根·弗里曼,鲍勃·冈顿
        </p>
<p class="releasetime">上映时间:1994-09-10(加拿大)</p>    </div>
    <div class="movie-item-number score-num">
<p class="score"><i class="integer">9.</i><i class="fraction">5</i></p>        
    </div>

      </div>
    </div>

                </dd>

这是其中的某一个电影信息的HTML,分析可知它的排名信息是在class为board-index的i节点内,利用非贪婪匹配来提取i节点内的信息,正则表达式可写为:                    <dd>.*?board-index.*?>(.*?)</i>

随后提取网页图片,其中第二个img节点的data-src属性是图片的链接,正则表达式写为:

<dd>.*?board-index.*?>(.*?)</i>.*?data-scr="(.*?)"

然后提取电影名称,在后面的p节点内,class为name。因此将name作为一个标志位,然后提取其中a节点的正文内容,正则表达式写为:

<dd>.*?board-index.*?>(.*?)</i>.*?data-scr="(.*?)".*?name.*?a.*?>(.*?)</a>

根据类似原理提取其中的主演、发布时间、评分等内容,最后正则表达式写为:

<dd>.*?board-index.*?>(\d+)</i>.*?data-scr="(.*?)".*?name"><a.*?>(.*?)</a>.*?star">(.*?)</p>.*?releasetime">(.*?)</p>.*?interger">(.*?)</i>.*?fraction">(.*?)</i>.*?</dd>

3.3 调用requests库,爬取HTML,并使用正则表达式提取对应内容

到了这一步,就需要开始写代码了,为了更加熟练地掌握函数式编程,本次代码编写也通过调用函数来实现。

首先分析要实现的内容应分为几个模块:

1,分页抓取网站的HTML

2,使用正则表达式解析网页

3,将结果写入文件

先写第一个模仿浏览器发出请求的函数:

def get_one_page(url):
    try:
        headers = {
            'User-Agent': 'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x32; rv:89.0) Gecko/20100101 Firefox/89.0'
        }
        response = requests.get(url, headers=headers)
        if response.status_code == 200:
            return response.text
        return None
    except RequestException:
        return None

该函数模拟了浏览器消息头的User-Agent信息,而后将响应信息返回。

接下来的是解析网页函数:

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

这段代码通过调用re库来实现正则表达式的使用(其中的正则表达式在经过了多次尝试后进行了数次微调),将匹配值整合成字典类型,然后运用yield函数实现迭代返回。

然后是写入文件的操作:

def write_to_file(content):
    with open(r"C:\Users\86153\Desktop\d.txt","a",encoding='utf-8') as f:
        f.write(json.dumps(content, ensure_ascii=False)+'\n')
        f.close()

而后,写出主函数,实现对各个函数的调用:

def main(offset):
    url = 'http://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)

最后,整合出整个程序:

from typing import Pattern
import requests
from requests.exceptions import RequestException
import re
import json
import time

def get_one_page(url):
    try:
        headers = {
            'User-Agent': 'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x32; rv:89.0) Gecko/20100101 Firefox/89.0'
        }
        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.*?>(\d+)</i>.*?data-scr="(.*?)".*?name"><a.*?>(.*?)</a>.*?star">(.*?)</p>.*?releasetime">(.*?)</p>.*?interger">(.*?)</i>.*?fraction">(.*?)</i>.*?</dd>',re.S)
    pattern = re.compile('<dd.*?board-index.*?>(.*?)</i>.*?data-src="(.*?)".*?alt="(.*?)"' \
                        '.*?class="star">(.*?)</p>.*?class="releasetime">(.*?)</p>' \
                        '.*?class="integer">(.*?)</i>.*?class="fraction">(.*?)</i>',re.S)
    items = re.findall(pattern, html)
    print(items)
    for item in items:
        yield {
            'index': item[0],
            'image': item[1],
            'title': item[2].strip(),
            'actor': item[3].strip()[3:],
            'time' : item[4].strip()[5:],
            'score': item[5] + item[6]
        }

def write_to_file(content):
    with open(r"C:\Users\86153\Desktop\d.txt","a",encoding='utf-8') as f:
        f.write(json.dumps(content, ensure_ascii=False)+'\n')
        f.close()

def main(offset):
    url = 'http://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):
        offset=i*10
        main(offset)
        time.sleep(1)

    f = open(r"C:\Users\86153\Desktop\d.txt","r",encoding='utf-8')
    f1 = open(r"C:\Users\86153\Desktop\e.txt","a",encoding='utf-8')
    for i in range(100):
        d = eval(f.readline())
        f1.write("排名:"+d.get('index')+'\n')
        f1.write("图片网址:"+d.get('image')+'\n')
        f1.write("电影名称:"+d.get('title')+'\n')
        f1.write("主演:"+d.get('actor')+'\n')
        f1.write("上映时间:"+d.get('time')+'\n')
        f1.write("电影评分:"+d.get('score')+'\n')

    f.close()
    f1.close()

在这里设置offset值的变化,并且设置延时1秒,防止过快发送消息导致无响应。

 

4. 实验结果

代码初步调试结果:

代码最终调试结果:

 

5. 实验过程中遇到的问题和解决过程

问题:猫眼电影网的反爬虫如何解决?

问题解决:每次访问时都更改自身消息头的User-Agent信息即可。

 

6. 实验体会

 在这次实验中,我练习了正则表达式与python的requests库、re库、json库的基本使用,基本掌握了最基础的使用,明确了爬虫程序编写的一个基本思路。

 

本次实验代码已上传至gitee     add 实验四. · c4dc525 · ZDM/python学习 - Gitee.com

 

posted @ 2021-06-30 22:25  MDZ-Z  阅读(123)  评论(0编辑  收藏  举报