可以看到每部电影信息都被包裹在一对<dd>...</dd>标签中,所以我们只需提取出一个标签对中的上述信息即可。使用正则表达式提取

3. 完整过程

这个例子有2个关键点:正则编写和数据处理(写进mysql数据库)
(1) 正则表达式的编写

    pattern = re.compile(r'<dd>.*?<i.*?>(\d+)</i>.*?'  # 匹配电影排名(加个?表示非贪婪匹配,不是匹配0次或1次)
                         r'<p class="name"><a.*?data-val=".*?">(.*?)'  # 匹配电影名称
                         r'</a>.*?<p.*?class="releasetime">(.*?)</p>'  # 匹配上映时间
                         r'.*?<i.*?"integer">(.*?)</i>'   # 匹配分数的整数位
                         r'.*?<i.*?"fraction">(.*?)</i>.*?</dd>', re.S)  # 匹配分数小数位,re.S表示跨行匹配
    m = pattern.findall(html)
    # print(m)

使用findall()方法来匹配所有符合规则的字符,返回一个列表,下面是其中一页的匹配结果

(2)完整代码,注意get_data()函数是如何处理数据,然后通过write_sql()函数是写入数据库的

# coding: utf-8
# author: hmk
import requests
import re
import pymysql
def get_html(url, header):
    response = requests.get(url, headers=header)
    if response.status_code == 200:
        return response.text
    else:
        return None
def get_data(html, list_data):
    pattern = re.compile(r'<dd>.*?<i.*?>(\d+)</i>.*?'  # 匹配电影排名
                         r'<p class="name"><a.*?data-val=".*?">(.*?)'  # 匹配电影名称
                         r'</a>.*?<p.*?class="releasetime">(.*?)</p>'  # 匹配上映时间
                         r'.*?<i.*?"integer">(.*?)</i>'  # 匹配分数的整数位
                         r'.*?<i.*?"fraction">(.*?)</i>.*?</dd>', re.S)  # 匹配分数小数位
    m = pattern.findall(html)
    for i in m:  # 因为匹配到的所有结果会以列表形式返回,每部电影信息以元组形式保存,所以可以迭代处理每组电影信息
        ranking = i[0]  # 提取一组电影信息中的排名
        movie = i[1]  # 提取一组电影信息中的名称
        release_time = i[2]  # 提取一组电影信息中的上映时间
        score = i[3] + i[4]  # 提取一组电影信息中的分数,这里把分数的整数部分和小数部分拼在一起
        list_data.append([ranking, movie, release_time, score])  # 每提取一组电影信息就放到一个列表中,同时追加到一个大列表里,这样最后得到的大列表就包含所有电影信息
def write_sql(data):
    conn = pymysql.connect(host='localhost',
                           user='root',
                           password='123456',
                           db='test',
                           charset='utf8')
    cur = conn.cursor()
    for i in data:
        """这里的data参数是指正则匹配并处理后的列表数据(是一个大列表,包含所有电影信息,每个电影信息都存在各自的一个列表中;
        对大列表进行迭代,提取每组电影信息,这样提取到的每组电影信息都是一个小列表,然后就可以把每组电影信息写入数据库了)"""
        movie = i  # 每组电影信息,这里可以看做是准备插入数据库的每组电影数据
        sql = "insert into maoyan_movie(ranking,movie,release_time,score) values(%s, %s, %s, %s)"  # sql插入语句
            cur.execute(sql, movie)  # 执行sql语句,movie即是指要插入数据库的数据
            conn.commit()  # 插入完成后,不要忘记提交操作
            print('导入成功')
        except:
            print('导入失败')
    cur.close()  # 关闭游标
    conn.close()  # 关闭连接
def main():
    start_url = 'http://maoyan.com/board/4'
    depth = 10  # 爬取深度(翻页)
    header = {"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
              "Accept-Encoding": "gzip, deflate, sdch",
              "Accept-Language": "zh-CN,zh;q=0.8",
              "Cache-Control": "max-age=0",
              "Connection": "keep-alive",
              "Host": "maoyan.com",
              "Referer": "http://maoyan.com/board",
              "Upgrade-Insecure-Requests": "1",
              "User-Agent": "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.75 Safari/537.36"}
    for i in range(depth):
        url = start_url + '?offset=' + str(10 * i)
        html = get_html(url, header)
        list_data = []
        get_data(html, list_data)
        write_sql(list_data)
        #print(list_data)
        # for i in list_data:
        #     t = i
        #     print(t)
if __name__ == "__main__":
    main()
注意一点,在请求url时,加了headers,这里必须加,估计是网站做了限制,直接爬的话会失败,可能认出请求链接的不是一个人而是一只虫了
代码中注释写得很详细,不再过多描述了