php网页抓取图片(一下如何抓取动态页面?抓取一个页面的方法十分简单)
优采云 发布时间: 2022-04-11 11:04php网页抓取图片(一下如何抓取动态页面?抓取一个页面的方法十分简单)
当我们要抓取一个页面的内容时,首先要做的不是写代码,而是分析页面,判断是静态页面还是动态页面。抓取静态页面的方法很简单。可以直接解析html源码,然后分析解析。不明白的可以参考我上一篇文章Scrapy抓取豆瓣电影资料。这里我主要介绍如何抓取。动态页面。
抓取动态页面有两种方法:
第一种方法是使用第三方工具模拟浏览器的行为来加载数据。例如:Selenium、PhantomJs。这种方法的优点是不必考虑动态页面的各种变化,但性能较低。
第二种方法是分析页面,找到对应的请求接口,直接获取数据。这种方式的优点是性能高,但缺点也很明显,就是获取API接口比较麻烦。
我这里用第二种方法爬取动态页面。
1.浏览器打开页面,查看网页源码,发现源码中没有图片信息。这是一个动态加载的页面,它是一个动态页面的异步ajax请求。
2.分析页面,提取API接口,通过F12可以找到review元素。
3.打开上面的url,发现传入的数据是json格式的,所以我们拿到response响应后,首先要使用json.loads()来解析数据。
4.观察API接口,可以发现有几个参数,ch、sn、listtype、temp,通过改变这些参数的值可以得到不同的内容。
通过分析发现,ch参数代表图片的分类。比如beauty代表美女图片,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.写一个管道完成数据持久化操作,包括下载图片和保存图片信息到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、pilllow、pymongo
pip install pypiwin32
pip install pillow
pip install pymongo
安装完成后就可以启动spider了
scrapy crawl image
10.查看结果:
获取到的图片返回的内容:
将图片保存到指定路径:
一个爬取动态页面和下载图片的爬虫就完成了。其实写起来很简单。关键是分析API接口,重写start_requests方法。