Python爬虫项目--爬取猫眼电影To

发布时间:2019-03-08 20:31:53编辑:auto阅读(2103)

     本次抓取猫眼电影Top100榜所用到的知识点:

    1. python requests库

    2. 正则表达式

    3. csv模块

    4. 多进程

    正文

    目标站点分析

    通过对目标站点的分析, 来确定网页结构, 进一步确定具体的抓取方式.

    1. 浏览器打开猫眼电影首页, 点击"榜单", 点击"Top100榜", 即可看到目标页面. 

    2.  浏览网页, 滚动到下方发现有分页, 切换到第2页, 发现: URL从 http://maoyan.com/board/4变换到http://maoyan.com/board/4?offset=10, 多次切换页码offset都有改变, 可以确定的是通过改变URL的offset参数来生成分页列表.

    项目流程框架:

    获取单页源码

     1 #抓取猫眼电影TOP100榜
     2 import requests
     3 import time
     4 from requests.exceptions import RequestException
     5 def get_one_page():
     6     '''获取单页源码'''
     7     try:
     8         url = "http://maoyan.com/board/4?offset={0}".format(0)
     9         headers = {
    10             "User-Agent":"Mozilla/5.0(WindowsNT6.3;Win64;x64)AppleWebKit/537.36(KHTML,likeGecko)Chrome/68.0.3440.106Safari/537.36"
    11         }
    12         res = requests.get(url, headers=headers)
    13         # 判断响应是否成功,若成功打印响应内容,否则返回None
    14         if res.status_code == 200:
    15             print(res.text)
    16         return None
    17     except RequestException:
    18         return None
    19 def main():
    20     get_one_page()
    21 if __name__ == '__main__':
    22     main()
    23     time.sleep(1)

    执行即可得到网页源码, 那么下一步就是解析源码了

    解析单页源码

    导入正则表达式re模块, 对代码进行解析, 得到想要的信息.

     1 import re
     2 
     3 def parse_one_page(html):
     4     '''解析单页源码'''
     5     pattern = re.compile('<dd>.*?board-index.*?>(\d+)</i>.*?name"><a.*?>(.*?)</a>.*?star">(.*?)</p>.*?releasetime'
     6                          + '.*?>(.*?)</p>.*?score.*?integer">(.*?)</i>.*?>(.*?)</i>.*?</dd>',re.S)
     7     items = re.findall(pattern,html)
     8     print(items)
     9     #采用遍历的方式提取信息
    10     for item in  items:
    11         yield {
    12             'rank' :item[0],
    13             'title':item[1],
    14             'actor':item[2].strip()[3:] if len(item[2])>3 else '',  #判断是否大于3个字符
    15             'time' :item[3].strip()[5:] if len(item[3])>5 else '',
    16             'score':item[4] + item[5]
    17         }
    18 def main():
    19     html = get_one_page()
    20     for item in parse_one_page(html):
    21         print(item)
    22 
    23 if __name__ == '__main__':
    24     main()
    25     time.sleep(1)

    提取出信息之后, 那么下一步就是保存到文件

    保存到文件中

    这里采用两种方式, 一种是保存到text文件, 另一种是保存到csv文件中, 根据需要选择其一即可.

    1. 保存到text文件

     1 import json
     2 
     3 def write_to_textfile(content):
     4     '''写入到text文件中'''
     5     with open("MovieResult.text",'a',encoding='utf-8') as f:
     6         #利用json.dumps()方法将字典序列化,并将ensure_ascii参数设置为False,保证结果是中文而不是Unicode码.
     7         f.write(json.dumps(content,ensure_ascii=False) + "\n")
     8         f.close()
     9 def main():
    10     html = get_one_page()
    11     for item in parse_one_page(html):
    12         write_to_textfile(item)
    13 
    14 if __name__ == '__main__':
    15     main()
    16     time.sleep(1)

    2. 保存到CSV文件

    其文件以纯文本的形式存储表格数据

     1 import csv
     2 def write_to_csvfile(content):
     3     '''写入到csv文件中'''
     4     with open("MovieResult.csv",'a',encoding='gb18030',newline='') as f:
     5         # 将字段名传入列表
     6         fieldnames = ["rank", "title", "actor", "time", "score"]
     7         #将字段名传给Dictwriter来初始化一个字典写入对象
     8         writer = csv.DictWriter(f,fieldnames=fieldnames)
     9         #调用writeheader方法写入字段名
    10         writer.writeheader()
    11         writer.writerows(content)
    12         f.close()
    13 def main():
    14     html = get_one_page()
    15     rows = []
    16     for item in parse_one_page(html):
    17         #write_to_textfile(item)
    18         rows.append(item)
    19     write_to_csvfile(rows)
    20 if __name__ == '__main__':
    21     main()
    22     time.sleep(1)

    单页的信息已经提取出, 接着就是提取多个页面的信息

    获取多个页面

    1. 普通方法抓取

     1 def main(offset):
     2     url = "http://maoyan.com/board/4?offset={0}".format(offset)
     3     html = get_one_page(url)
     4     rows = []
     5     for item in parse_one_page(html):
     6         #write_to_textfile(item)
     7         rows.append(item)
     8     write_to_csvfile(rows)
     9 if __name__ == '__main__':
    10     #通过遍历写入TOP100信息
    11     for i in range(10):
    12         main(offset=i * 10)
    13         time.sleep(1)

    2. 多进程抓取

    1 from multiprocessing import Pool
    2 
    3 if __name__ == '__main__':
    4     # 将字段名传入列表
    5     fieldnames = ["rank", "title", "actor", "time", "score"]
    6     write_to_csvField(fieldnames)
    7     pool = Pool()
    8     #map方法会把每个元素当做函数的参数,创建一个个进程,在进程池中运行.
    9     pool.map(main,[i*10 for i in range(10)])

     完整代码

     1 #抓取猫眼电影TOP100榜
     2 from multiprocessing import Pool
     3 from requests.exceptions import RequestException
     4 import requests
     5 import json
     6 import time
     7 import csv
     8 import re
     9 def get_one_page(url):
    10     '''获取单页源码'''
    11     try:
    12         headers = {
    13             "User-Agent":"Mozilla/5.0(WindowsNT6.3;Win64;x64)AppleWebKit/537.36(KHTML,likeGecko)Chrome/68.0.3440.106Safari/537.36"
    14         }
    15         res = requests.get(url, headers=headers)
    16         # 判断响应是否成功,若成功打印响应内容,否则返回None
    17         if res.status_code == 200:
    18             return res.text
    19         return None
    20     except RequestException:
    21         return None
    22 def parse_one_page(html):
    23     '''解析单页源码'''
    24     pattern = re.compile('<dd>.*?board-index.*?>(\d+)</i>.*?name"><a.*?>(.*?)</a>.*?star">(.*?)</p>.*?releasetime'
    25                          + '.*?>(.*?)</p>.*?score.*?integer">(.*?)</i>.*?>(.*?)</i>.*?</dd>',re.S)
    26     items = re.findall(pattern,html)
    27     #采用遍历的方式提取信息
    28     for item in  items:
    29         yield {
    30             'rank' :item[0],
    31             'title':item[1],
    32             'actor':item[2].strip()[3:] if len(item[2])>3 else '',  #判断是否大于3个字符
    33             'time' :item[3].strip()[5:] if len(item[3])>5 else '',
    34             'score':item[4] + item[5]
    35         }
    36 
    37 def write_to_textfile(content):
    38     '''写入text文件'''
    39     with open("MovieResult.text",'a',encoding='utf-8') as f:
    40         #利用json.dumps()方法将字典序列化,并将ensure_ascii参数设置为False,保证结果是中文而不是Unicode码.
    41         f.write(json.dumps(content,ensure_ascii=False) + "\n")
    42         f.close()
    43 
    44 def write_to_csvField(fieldnames):
    45     '''写入csv文件字段'''
    46     with open("MovieResult.csv", 'a', encoding='gb18030', newline='') as f:
    47         #将字段名传给Dictwriter来初始化一个字典写入对象
    48         writer = csv.DictWriter(f,fieldnames=fieldnames)
    49         #调用writeheader方法写入字段名
    50         writer.writeheader()
    51 def write_to_csvRows(content,fieldnames):
    52     '''写入csv文件内容'''
    53     with open("MovieResult.csv",'a',encoding='gb18030',newline='') as f:
    54         #将字段名传给Dictwriter来初始化一个字典写入对象
    55         writer = csv.DictWriter(f,fieldnames=fieldnames)
    56         #调用writeheader方法写入字段名
    57         #writer.writeheader()            ###这里写入字段的话会造成在抓取多个时重复.
    58         writer.writerows(content)
    59         f.close()
    60 
    61 def main(offset):
    62     fieldnames = ["rank", "title", "actor", "time", "score"]
    63     url = "http://maoyan.com/board/4?offset={0}".format(offset)
    64     html = get_one_page(url)
    65     rows = []
    66     for item in parse_one_page(html):
    67         #write_to_textfile(item)
    68         rows.append(item)
    69     write_to_csvRows(rows,fieldnames)
    70 
    71 if __name__ == '__main__':
    72     # 将字段名传入列表
    73     fieldnames = ["rank", "title", "actor", "time", "score"]
    74     write_to_csvField(fieldnames)
    75     # #通过遍历写入TOP100信息
    76     # for i in range(10):
    77     #     main(offset=i * 10,fieldnames=fieldnames)
    78     #     time.sleep(1)
    79     pool = Pool()
    80     #map方法会把每个元素当做函数的参数,创建一个个进程,在进程池中运行.
    81     pool.map(main,[i*10 for i in range(10)])

    效果展示: 

    最终采用写入csv文件的方式.

关键字