【爬虫】爬取猫眼电影top100

用正则表达式爬取

#!/usr/bin/python
# -*- coding: utf-8 -*-

import json     #  快速导入此模块:鼠标先点到要导入的函数处,再Alt + Enter进行选择
from multiprocessing.pool import Pool  #引入进程池

import requests
import re
import csv
from requests.exceptions import RequestException   #引入异常

## 正确保存,无丢失

# 请求一个页面返回响应内容
#以《霸王别姬》为列,右击—查看元素—会显示一个网页信息
def get_one_page(url,offset):
    try:
        response=requests.get(url=url,params={"offset":offset})
        if response.status_code==200:   #由状态码判断返回结果,200表示请求成功,300,500表出错
            return response.text   #返回网页内容
        else:return None
    except RequestException as e:
            return None

# 解析一个页面
def parse_one_page(html):
    pattern = ('<dd>.*?board-index.*?>(\d+)</i>.*?data-src="(.*?)".*?name"><a'
                         + '.*?>(.*?)</a>.*?star">(.*?)</p>.*?releasetime">(.*?)</p>'
                         + '.*?integer">(.*?)</i>.*?fraction">(.*?)</i>.*?</dd>')
    #写个正则,匹配所有结果。这里由上面的网页相应内容写<dd>开头,.*?匹配任意字符穿  board-index匹配标识符,类名,
    # \d 表数字即排名,'+'表示匹配至少一个可多个数字,</i>右边结束符
    #“?”,问号表示  非贪婪匹配,就是一旦匹配到就不在继续往后面尝试。
    #而\(和\)分别表示匹配一个“(”和“)”
    # re.S匹配多行
    regex = re.compile(pattern,re.S)   #一个方法,通过一个正则表达式字符串编译生成一个正则表达式对象,re.S 匹配任意字符
    items = regex.findall(html)    #以列表形式返回全部能匹配的子串. eg: re.findall(pattern, string[, flags])
    for item in items:    #将结果以字典形式返回,键值对
         yield{        #把这个方法变成一个生成器
             'index':item[0],
             'image':item[1],
             'title':item[2],
             'actor':item[3].strip()[3:],   #用strip()去掉换行符,不想要 主演: 这三个字就用[3:]组成一个切片,name就可以将前三个字符串去掉
             'time':get_release_time(item[4].strip()[5:]),     #去掉前五个字符
             'area':get_release_area(item[4].strip()[5:]),
             'score':item[5]+item[6]    #将评分整数部分和小数部分结合起来
        }

'''
#保存到txt,会发现中文汉字变成了unic的编码,加上encoding='utf-8',ensure_ascii=False,则汉字可正常输出
def  write_to_file(content):
    with open('result.txt','a',encoding='utf-8') as f:   # 参数 a ,表示直接往后追加
        f.write(json.dumps(content,ensure_ascii=False) +'\n')    #content是一个字典的形式,用json.dumps 把它转换为字符串,再加个换行符
        f.close()    
#json.dumps :dict 转换为 str 
#json.loads: str 转换为 dict
'''
''''''
# 获取上映时间   <p class="releasetime">上映时间:1993-01-01(中国香港)</p>
def get_release_time(data):
    pattern = '^(.*?)(\(|$)'
    regex = re.compile(pattern)
    w = regex.search(data)
    return w.group(1)   # group(1)指的是第一个括号里的东西

# 获取上映地区
def get_release_area(data):
    pattern = '.*\((.*)\)' #而\(和\)分别表示匹配一个 '(' 和 ')'
    regex = re.compile(pattern)
    w = regex.search(data)
    if w is None:
        return'未知'
    return w.group(1)

# 获取封面大图,不需要
# def get_large_thumb(url):
#     pattern = '(.*?)@.*?'
#     regex = re.compile(pattern)
#     w = regex.search(url)
#     return w.group(1)

# 存储数据
def store_data(item):
    with open('movie.csv','a',newline='',encoding='utf-8') as data_csv:
        # dialect为打开csv文件的方式,默认是excel,delimiter="\t"参数指写入的时候的分隔符
        csv_writer = csv.writer(data_csv)
        csv_writer.writerow([item['index'], item['image'], item['title'], item['actor'],item['time'],item['area'],item['score']])
# 参数newline是用来控制文本模式之下,一行的结束字符。可以是None,’’,\n,\r,\r\n等。
'''
也可判断异常,一般没错
        try:
            csv_writer = csv.writer(data_csv)
            csv_writer.writerow([item['index'], item['image'], item['title'], item['actor'],item['time'],item['area'],item['score']])
        except Exception as e:
            print(e)
            print(item)
'''

# 下载封面图
#读方式打开的话,并不会新建;写方式打开的话就会新建。  r只读,w可写,a追加
def download_thumb(title,image):
    try:
        response = requests.get(image)
        # 获取二进制数据
        with open('image/'+title+'.jpg', 'wb') as f:   #将封面图保存到当前路径下的image文件夹中,图片名称为:电影名.jpg
            f.write(response.content)
            f.close()
    except RequestException as e:
        print(e)
        pass


# 主调度程序
def main():
    # 起始URL
    start_url = 'http://maoyan.com/board/4?'
    for i in range(0,1000,10):
        # 获取响应文本内容
        html = get_one_page(url=start_url, offset=i)
        if html is None:
            print('链接:%s?offset=%s异常'.format(start_url,i))
            continue
        for item in parse_one_page(html):
            # print(item)
            store_data(item)
            # download_thumb(item['title'],item['image'])
#

if __name__=='__main__':
    main()

'''
if __name__=='__main__':
    for i in range(10):
        main(i*10)
'''

'''
if __name__=='__main__':
    for i in range(10):
        main(i*10)
    pool=Pool()   #可以提供指定数量的进程供用户调用,如果有一个新的请求被提交到进程池,进程池还没有满,就会创建新的进程来执行请求,如果满了,就先等待
    pool.map(main,[i*10 for i in range(10)]) #将数组中的每一个元素拿出来当做函数的参数,然后创建一个个的进程,放到进程池里面去运行;第二个参数是构造一个数组,组成循环
    #速度明显变快!1s
'''
保存到数据库

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['number'])   #能正确输出  , charset="utf8"
    try:
        conn = pymysql.connect(host='localhost', user='root', passwd=' ', port=3306,db='test1',charset="utf8",use_unicode = False )
        cur = conn.cursor()  # 创建一个游标对象
        for item in parse_one_page(html):
            try:
                # sql = "INSERT INTO movies (number,picture,title,actors,time,area,score) VALUES (%s,%s,%s,%s,%s,%s,%s)"
                # cur.execute(sql, ( item['number'],item['picture'],item['title'],item['actors'],item['time'],item['area'],item['score']))
                sql = "insert into test_movies (number,picture,title,actors,time,area,score) values(%s,%s,%s,%s,%s,%s,%s)"
                cur.execute(sql, (item['number'], item['picture'], item['title'], item['actors'], item['time'], item['area'],item['score']))
            except pymysql.Error as e:
                print(e)
            print('- - - - - 数据保存成功 - - - - -')
        conn.commit()
        cur.close()
        conn.close() # 关闭数据
    except pymysql.Error as e:
        print("Mysql Error %d: %s" % (e.args[0], e.args[1]))


if __name__=='__main__':
   # 连接数据库
   conn = pymysql.connect(host='localhost', user='root', passwd=' ', port=3306, db='test1', charset="utf8")
   cur = conn.cursor()  # 创建一个游标对象
   cur.execute("DROP TABLE IF EXISTS test_movies")  # 如果表存在则删除
   # 创建表sql语句
   sqlc = """CREATE TABLE test_movies(
       number int not null primary key auto_increment,
       picture VARCHAR(100) NOT NULL,
       title VARCHAR(100) NOT NULL,
       actors VARCHAR(200) NOT NULL,
       time VARCHAR(100) NOT NULL,
       area VARCHAR(100) ,
       score VARCHAR(50) NOT NULL
   )"""
   cur.execute(sqlc)  # 执行创建数据表操作
   pool=Pool()
   pool.map(main,[i*10 for i in range(10)])


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值