本次爬取猫眼电影采用requests库做网络请求,正则表达式做HTML网页解析,多线程方式进行爬取,最后数据序列化成json格式数据并保存。
从图片中可以看出 url的变化规律为:
http://maoyan.com/board/4?offset=页数*10
当然,页数是从0开始的。
从图片中可以看出每一部电影区块都是由一个dd标签组成,而我们所要提取的信息都在这个dd标签里面。所以得出一个贪婪正则表达式为:
其中()
里面的就是每一个我们要提交的字段信息
import threading #多线程
import requests, re, json#网络请求、正则、数据序列化
from requests.exceptions import RequestException #请求异常
from multiprocessing import Process #多进程
from multiprocessing import Pool #进程池
def get_one_page(url): #传入url地址
try:
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36"
} #定义一个字典形式的请求头,加入User-Agent为key的参数,用来模拟浏览器请求
response = requests.get(url, headers=headers) #请求url
with open('result.html', 'w', encoding='utf-8') as f: #把url以文件形式写入到本地,利于方便看html代码来分析
f.write(response.text)
f.close()
if response.status_code == 200: #如果网路请求成功,返回html代码
return response.text
return None #否则返回空
except RequestException: #捕获请求异常
print("异常")
return None
def parse_html(html):
pattern = re.compile(
'.*?>(\d+).*?data-src="(.*?)".*?"name">(.*?).*?class="star">(.*?).*?releasetime">(.*?).*?integer">(.*?).*?fraction">(.*?).*? ',
re.S) #生成一个正则表达式对象
items = re.findall(pattern, html) #通过正则表达式对象和网页html代码匹配到我们需要的数据,赋值给items
# print(items)
for item in items: #每一项数据用yield返回一个字典出去,形成一个生成器
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('maoyantop100.txt', 'a', encoding='utf-8') as f:
f.write(json.dumps(content, ensure_ascii=False) + '\n')
f.close()
list=[] #定义一个列表,用于把每一个字典(也就是每一部电影的信息)存放进去
def main(offset):
url = "http://maoyan.com/board/4?offset="+str(offset)
html = get_one_page(url)
for item in parse_html(html):
list.append(item)
最后在执行文件入口执行以上方法:
# for循环方式来爬取
# for i in range(10):
# main(i*10)
#进程方式执行 起了十个进程来爬取,为了保证抓取完成也就是进程执行完毕,加入p.join()方法来保证进程执行完,当前程序才退出,但是这样会使爬取效率降低
# processes = [Process(target=main,args=(i*10,) ) for i in range(10)] # 用列表生成式 生成10个线程
# for p in processes:
# p.start() # 启动刚刚创建的10个进程
# p.join() # 进程结束 主进程也就是当前的程序 才结束
# print('master process finished...')
#
# #进程池 多进程的方式来爬取
# def end(arg):# 单个进程结束执行的方法
# print("processes finish")
# pool = Pool(5)
# for i in range(10):
# pool.apply(main,args=(i*10,)) #串行执行
# # pool.apply_async(func=main, args=(i*10,), callback=end) # 并行执行,callback,是进程结束后的回调,是主进程调用的回调。
# pool.close() # 需先close,再join
# pool.join() # join: 等待子进程,主线程再结束
# print('main finished...')
#多线程方式爬取 启动十个线程来爬取,爬取速度及其快,可以实现秒获取
threads=[ threading.Thread(target=main,args=(i*10,)) for i in range(10)] #用列表生成式 生成10个线程
for t in threads: #启动刚刚创建的10个线程
t.start()
t.join() #加入join后 ,子线程结束,主线程才结束,运行速度会变慢
print(json.dumps(list))
write_to_file(list)
完整代码地址:https://github.com/domain9065/maoyantop100