抓取动态网页(一下如何抓取动态页面?抓取一个页面的方法十分简单)
优采云 发布时间: 2021-11-17 03:02抓取动态网页(一下如何抓取动态页面?抓取一个页面的方法十分简单)
当我们要抓取一个页面的内容时,首先要做的不是写代码,而是分析页面,判断是静态页面还是动态页面。抓取静态页面的方法很简单。只需解析html源代码,分析分析即可。不明白的可以参考我之前的文章文章Scrapy抓取豆瓣电影信息。这里我主要讲讲怎么抢。动态页面。
获取动态页面有两种方式:
第一种方法是使用第三方工具来模拟浏览器加载数据的行为。例如:Selenium、PhantomJs。这种方法的优点是不需要考虑动态页面的各种变化,但性能较低。
第二种方法是分析页面,找到对应的请求接口,直接获取数据。这种方式的优点是性能高,但是缺点也很明显,就是获取API接口比较麻烦。
这里我使用第二种方法来获取动态页面。
1. 在浏览器中打开页面,查看网页源码,发现源码中没有图片信息。这是一个动态加载的页面,是ajax异步请求的动态页面。
2.分析页面,提取API接口,通过F12,可以找到review元素。
3.打开上面的url,发现传入的数据是json格式的,所以我们得到响应响应后,首先要使用json.loads()解析数据。
4. 观察API接口,可以发现有几个参数,ch,sn,listtype,temp。通过改变这些参数的值可以得到不同的内容。
通过分析发现ch参数代表的是图片分类。例如,beautiful代表一张漂亮的图片,sn代表图片的编号,例如0代表1到30之间的图片,30代表31到60之间的图片。
分析完这些参数,我们就确定了我们需要请求的url地址。这里的url不像a标签中的href在静态页面中是通过程序自动获取的,而是需要我们自动设置。我们可以通过覆盖 start_requests 方法 指定要获取的 url。
5.写我们的蜘蛛
# -*- coding: utf-8 -*- from json import loads import scrapy from urllib.parse import urlencode from image360.items import BeautyItem class ImageSpider(scrapy.Spider): name = 'image' allowed_domains = ['image.so.com'] # 重写Spider中的start_requests方法:指定开始url def start_requests(self): base_url = 'http://image.so.com/zj?' param = {'ch': 'beauty', 'listtype': 'new', 'temp': '1'} # 可以根据需要爬取不同数量的图片,此处只爬取60张图片 for page in range(2): param['sn'] = page * 30 full_url = base_url + urlencode(param) yield scrapy.Request(url=full_url, callback=self.parse) def parse(self, response): # 获取到的内容是json数据 # 用json.loads()解析数据 # 此处的response没有content model_dict = loads(response.text) for elem in model_dict['list']: item = BeautyItem() item['title'] = elem['group_title'] item['tag'] = elem['tag'] item['height'] = elem['cover_width'] item['width'] = elem['cover_height'] item['url'] = elem['qhimg_url'] yield item
6.写入项目并定义保存的字段
import scrapy class BeautyItem(scrapy.Item): title = scrapy.Field() tag = scrapy.Field() height = scrapy.Field() width = scrapy.Field() url = scrapy.Field()
7.编写pipeline完成数据持久化操作,包括下载图片和保存图片信息到mongo。
Scrapy 提供了一个项目管道来下载属于特定项目的图片。例如,当您抓取一个产品并希望将其图片下载到本地时,您可以通过图片管道来实现。这是在 ImagesPipenine 类中实现的,它提供了一种方便且功能额外的方法来下载和本地存储图片。这个类提供了很多处理图片的方法,想了解详细可以查看中文版官方文档
# -*- coding: utf-8 -*- import logging import pymongo import scrapy from scrapy.exceptions import DropItem from scrapy.pipelines.images import ImagesPipeline logger = logging.getLogger('SaveImagePipeline') # 继承ImagesPipenine类,这是图片管道 class SaveImagePipeline(ImagesPipeline): """ 下载图片 """ def get_media_requests(self, item, info): # 此方法获取的是requests 所以用yield 不要return yield scrapy.Request(url=item['url']) def item_completed(self, results, item, info): """ 文件下载完成之后,返回一个列表 results 列表中是一个元组,第一个值是布尔值,请求成功会失败,第二个值的下载到的资源 """ if not results[0][0]: # 如果下载失败,就抛出异常,并丢弃这个item # 被丢弃的item将不会被之后的pipeline组件所处理 raise DropItem('下载失败') # 打印日志 logger.debug('下载图片成功') return item def file_path(self, request, response=None, info=None): """ 返回文件名 """ return request.url.split('/')[-1] class SaveToMongoPipeline(object): """ 保存图片信息到数据库 """ def __init__(self, mongodb_server, mongodb_port, mongodb_db, mongodb_collection): self.mongodb_server = mongodb_server self.mongodb_port = mongodb_port self.mongodb_db = mongodb_db self.mongodb_collection = mongodb_collection def open_spider(self, spider): # 当spider被开启时,这个方法被调用 self.connection = pymongo.MongoClient(self.mongodb_server, self.mongodb_port) db = self.connection[self.mongodb_db] self.collection = db[self.mongodb_collection] def close_spider(self, spider): # 当spider被关闭时,这个方法被调用。 self.connection.close() # 依赖注入 @classmethod def from_crawler(cls, crawler): # cls() 会调用初始化方法 return cls(crawler.settings.get('MONGODB_SERVER'), crawler.settings.get('MONGODB_PORT'), crawler.settings.get('MONGODB_DB'), crawler.settings.get('MONGODB_COLLECTION')) def process_item(self, item, spider): post = {'title': item['title'], 'tag': item['tag'], 'width': item['width'], 'height': item['height'], 'url': item['url']} self.collection.insert_one(post) return item
8.写入设置并完成配置。这里只写需要配置的内容。
9.启动蜘蛛
在启动spider之前,我们需要安装几个包,pypiwin32、pillow, pymongo
pip install pypiwin32 pip install pillow pip install pymongo
安装完成后就可以启动spider了
scrapy crawl image
10.查看结果:
获取到的图片返回的内容:
图片保存在指定路径:
一个爬取动态页面和下载图片的爬虫就完成了。其实写起来很简单。关键是分析API接口,重写start_requests方法。