1、说明
- 创建一个工程:scrapy startproject xxxPro
- cd xxxPro
- 在spiders子目录中创建一个爬虫文件
- scrapy genspider spiderName www.xxx.com
- 执行工程:
- scrapy crawl spiderName
scrapy的五大核心组件:
组件 | 介绍 |
---|---|
引擎(Scrapy) | 用来处理整个系统的数据流处理, 触发事务(框架核心) |
调度器(Scheduler) | 用来接受引擎发过来的请求, 压入队列中, 并在引擎再次请求的时候返回. 可以想像成一个URL(抓取网页的网址或者说是链接)的优先队列, 由它来决定下一个要抓取的网址是什么, 同时去除重复的网址 |
下载器(Downloader) | 用于下载网页内容, 并将网页内容返回给蜘蛛(Scrapy下载器是建立在twisted这个高效的异步模型上的) |
爬虫(Spiders) | 爬虫是主要干活的, 用于从特定的网页中提取自己需要的信息, 即所谓的实体(Item)。用户也可以从中提取出链接,让Scrapy继续抓取下一个页面 |
项目管道(Pipeline) | 负责处理爬虫从网页中抽取的实体,主要的功能是持久化实体、验证实体的有效性、清除不需要的信息。当页面被爬虫解析后,将被发送到项目管道,并经过几个特定的次序处理数据。 |
2、站长图片爬取
#创建scrapy项目和爬虫文件
scrpay startproject imgpro
cd imgpro
scrapy genspider img
#系统自动生成xiaoh.py爬虫文件
1、对img.py文件编写,实现网页的爬取和数据解析。
import scrapy
from imgpro.items import ImgproItem
class ImgSpider(scrapy.Spider):
name = 'img'
# allowed_domains = ['ww']
start_urls = ['http://sc.chinaz.com/tupian/']
base_url = 'http://sc.chinaz.com/tupian/index_%d.html'
page_num = 2 #分页标记页
def parse(self, response):
#获取当前页面所有图片dix标签
div_list = response.xpath('//div[@id="container"]/div')
for div in div_list:
#对每张图片进行src和名称爬取
src = div.xpath('./div/a/img/@src2').extract_first()
name = div.xpath('./p/a/text()').extract()[0]
name = str(''.join(name)).replace('图片', '') + '.jpg'
#导入框架中的ImgproItem类,在ImgproItem添加name和src属性,在items.py脚本中
#src = scrapy.Field()
#name = scrapy.Field()
item = ImgproItem()
item['src'] = src
item['name'] = name
yield item #在整个项目当中就能使用item
#开始分页
if self.page_num <= 200:
print('第%d页爬取成功!!!' % (self.page_num))
#拼接下一页的url
new_url = format(self.base_url % self.page_num)
self.page_num += 1
#Request传入新的url和callback回调解析方法
yield scrapy.Request(new_url, callback=self.parse)
2、在pipelines.py中可以对获取的数据进行持久化储存,对于图片,scrapy有特定的类来实现储存。
from scrapy.pipelines.images import ImagesPipeline
import scrapy
class imgsPileLine(ImagesPipeline):
#就是可以根据图片地址进行图片数据的请求
def get_media_requests(self, item, info):
#使用meta来传参
yield scrapy.Request(item['src'], meta={'item':item})
#指定图片存储的路径
def file_path(self, request, response=None, info=None):
imgName = request.meta['item']['name']
return imgName
def item_completed(self, results, item, info):
return item #返回给下一个即将被执行的管道类
3、到这里我们的代码就已经编写好了,但是需要对项目进行设置,在settings.py文件中。
#UA伪装
USER_AGENT = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36'
ROBOTSTXT_OBEY = False
#只打印错误的信息
LOG_LEVEL = 'ERROR'
#开启imgsPileLine管道
ITEM_PIPELINES = {
'imgpro.pipelines.imgsPileLine': 300,
}
#图片储存的路径
IMAGES_STORE = './img_zhx'
然后就直接scrapy crawl img就可以运行了。
3、中间件的使用(网易新闻)
网易新闻实例只爬取了国内和国外两栏的新闻。
因为网易云新闻的数据是动态加载出来的,所以我们使用了selenium来进行动态化的爬取。
1、对wangyi.py文件编写,实现网页的爬取和数据解析。
import scrapy
from wangyiPro.items import WangyiproItem
from selenium import webdriver
class WangyiSpider(scrapy.Spider):
name = 'wangyi'
# allowed_domains = ['news.163.com']
start_urls = ['http://news.163.com/']
li_url_list = []
def __init__(self):
self.bro = webdriver.Chrome(executable_path='D:\workspace\chromedriver.exe')
def parse(self, response):
wangyi_list = [6, 7]
li_list = response.xpath('//*[@id="index2016_wrap"]/div[1]/div[2]/div[2]/div[2]/div[2]/div/ul/li')
for index in wangyi_list:
li_url = li_list[index].xpath('./a/@href').extract_first()
print(li_url)
self.li_url_list.append(li_url)
# 依次对每一个板块对应的页面进行请求
for url in self.li_url_list: # 对每一个板块的url进行请求发送
yield scrapy.Request(url, callback=self.parse_model)
def parse_model(self, response):
div_list = response.xpath('/html/body/div[1]/div[3]/div[4]/div[1]/div/div/ul/li/div/div')
for div in div_list:
title = div.xpath('./div/h3/a/text() | ./div/div[1]/h3/a/text()').extract_first()
new_detial_url = div.xpath('./div/h3/a/@href | ./div/div[1]/h3/a/@href').extract_first()
if title == None:
continue
print(title, new_detial_url)
item = WangyiproItem()
item['title'] = title
yield scrapy.Request(url=new_detial_url, callback=self.parse_detail, meta={'item': item})
def parse_detail(self, response):
# p_list = response.xpath('//*[@id="endText"]/p')
# content_list = []
# for p in p_list:
# p_text = p.xpath('./text()').extract_first()
# content_list.append(p_text)
# content = ''.join('%s' %id for id in content_list)
# item = response.meta['item']
# item['content'] = content
content = response.xpath('//*[@id="endText"]//text()').extract()
content = ''.join(content)
item = response.meta['item']
item['content'] = content
yield item
def closed(self, spider):
self.bro.quit()
2、在pipelines.py中可以对获取的数据进行持久化储存,对于图片,scrapy有特定的类来实现储存。
from itemadapter import ItemAdapter
class WangyiproPipeline:
fp = None
def open_spider(self, spider):
print('开始爬虫')
self.fp = open('./wangyi.txt', 'w', encoding='utf-8')
# 处理item,接受一次调用一次
def process_item(self, item, spider):
title = item['title']
content = item['content']
self.fp.write(title + ':' + content + '\n'+'*'*100+'\n')
return item
def close_spider(self, spider):
print('爬虫结束!!')
self.fp.close()
3、主要是使用下载中间件的process_response方法。
#该方法拦截五大板块对应的响应对象,进行篡改
def process_response(self, request, response, spider):#spider爬虫对象
bro = spider.bro#获取了在爬虫类中定义的浏览器对象
#挑选出指定的响应对象进行篡改
#通过url指定request
#通过request指定response
if request.url in spider.models_urls:
bro.get(request.url) #五个板块对应的url进行请求
sleep(3)
page_text = bro.page_source #包含了动态加载的新闻数据
#response #五大板块对应的响应对象
#针对定位到的这些response进行篡改
#实例化一个新的响应对象(符合需求:包含动态加载出的新闻数据),替代原来旧的响应对象
#如何获取动态加载出的新闻数据?
#基于selenium便捷的获取动态加载数据
new_response = HtmlResponse(url=request.url,body=page_text,encoding='utf-8',request=request)
return new_response
else:
#response #其他请求对应的响应对象
return response
4、到这里我们的代码就已经编写好了,但是需要对项目进行设置,在settings.py文件中。
#UA伪装
USER_AGENT = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36'
ROBOTSTXT_OBEY = False
#只打印错误的信息
LOG_LEVEL = 'ERROR'
#开启WangyiproPipeline管道
ITEM_PIPELINES = {
'wangyiPro.pipelines.WangyiproPipeline': 300,
}
#开启下载中间件
DOWNLOADER_MIDDLEWARES = {
'wangyiPro.middlewares.WangyiproDownloaderMiddleware': 543,
}
然后就直接scrapy crawl wangyi就可以运行了。