注意:此处为主代码,,还需要设置一些,具体请参考下面基本步骤的内容
# -*- coding: utf-8 -*-
# -*- coding:utf-8 -*-
#爬虫框架:Scrapy PySpider Selenium(其中1,3必须会)
#其中Selenium自动测试的一个框架
#打开项目步骤(项目在桌面):看图片
#如果文件夹下存在__init__文件,,证明是一个包,删除就变成一个普通的文件夹
#.............仍是爬取天堂图片网..................
#在终端创建项目(看老师发的图片) scrapy startproject IvskySpider
#创建文件,不在终端,在pycharm终端,,看图片,
#打开文件
#注意:爬虫名称必须唯一,一般不改
#2.域名如果不存在,就不会爬取
#3.网址一般需要手动重新设置,可以存放多个网址
import scrapy
import os
import requests
#
#一个点(.)表示当前文件所在文件夹,两个点表示文件夹的文件夹
from ..items import ImgInfoItem
#此处不用导入,因为scrapy框架自带一种解析方式,基于lxml
#from lxml import etree
class IvskySpider(scrapy.Spider):
name = 'ivsky'
allowed_domains = ['ivsky.com']
start_urls = ['http://www.ivsky.com/tupian/ziranfengguang/']
def parse(self, response):
#这里的response跟之前的不是太一样,没有content属性
# print(response.text)
#常规写法,调用函数
# self.parse_big_category(response)
#框架中的写法,用yield调用函数节省时间
"""
参数一:url,爬取的网址
参数2:callback回调,当网页下载好之后传给谁去解析
参数三:method,默认get
hesders
cookies
meta
"""
#解析大分类
yield scrapy.Request(
url=response.url,
#注意:此处不带圆括号
callback=self.parse_big_category,
#scrapy会自动过滤已经爬过的地址,因此设置为true,表示不过滤
dont_filter=True,
)
#解析大分类
def parse_big_category(self,response):
"""
解析网页大分类
:param response:
:return:
"""
#以下三种解析方式都可以用,但是推荐使用xpath
# response.selector.xpath()
#以上一句简写
big_a_list = response.xpath("//ul[@class='tpmenu']/li/a")
for big_a in big_a_list[1:]:
#extract_first()将列表中的元素转换成字符串并且取第0个,如果取不到,就返回默认值
big_title = big_a.xpath("text("
")").extract_first("没有标题")
big_href = big_a.xpath("@href").extract_first("没有地址")
big_href="http://www.ivsky.com"+big_href
#在大分类中解析小分类
yield scrapy.Request(
url=big_href,
callback=self.parse_small_category,
#meta负责传递数据,参数类型一般是个字典
meta={
"big_title":big_title
},
dont_filter = True
)
# print(big_title,big_href)
# response.selector.css()
# response.selector.re()
#解析小分类
def parse_small_category(self,response):
"""
解析网页小分类
:param response:
:return:
"""
#拿大分类标题,meta是response的属性
# big_title = response.meta.get("big_title")
small_a_list = response.xpath("//div["
"@class='sline']/div/a")
for small_a in small_a_list:
small_title = small_a.xpath("text("
")").extract_first(
"没有标题")
#在原有基础上增加一个字段 添加小标题
response.meta['small_title'] = small_title
small_href = small_a.xpath(
"@href").extract_first("没有地址")
small_href = "http://www.ivsky.com" +small_href
# print(small_title,small_href)
yield scrapy.Request(
url=small_href,
callback=self.parse_img_list,
# meta={
# "big_title": big_title,
# "small_title":small_title
# }
meta=response.meta,
dont_filter=True
)
#解析图片列表
def parse_img_list(self,response):
"""
解析图片缩略图
:param response:
:return:
"""
img_a_list = response.xpath("//ul[@class='pli']/li/div/a")
for img_a in img_a_list:
detail_href = img_a.xpath(
"@href").extract_first("没有详情地址")
detail_href="http://www.ivsky.com"+detail_href
thumb_src = img_a.xpath(
"img/@src").extract_first("没有图片地址")
thumb_alt = img_a.xpath(
"img/@alt").extract_first(
"没有图片名称")
response.meta['thumb_src'] = thumb_src
response.meta['thumb_alt'] = thumb_alt
# print(thumb_alt,thumb_src)
yield scrapy.Request(
url=detail_href,
callback=self.parse_img_detail,
meta=response.meta,
dont_filter=True
)
# 解析大图
def parse_img_detail(self, response):
"""
解析图片详情
:param response:
:return:
"""
big_title = response.meta.get(
"big_title").strip()
small_title = response.meta.get(
"small_title").strip()
thumb_src = response.meta.get("thumb_src").strip()
thumb_alt = response.meta.get("thumb_alt").strip()
img_detail_src = response.xpath("//img[@id='imgis']/@src").extract_first("没有图片详情地址")
# print(img_detail_src)
path = "total/"+big_title+"/"+small_title+"/"+thumb_alt
if not os.path.exists(path):
os.makedirs(path)
picture_name = thumb_src.split('/')[-1]
thumb_name = "缩略图"+picture_name
detail_name = "高清图"+picture_name
# 创建对象
item = ImgInfoItem()
item['big_title']=big_title
item['small_title']=small_title
item['thumb_src']=thumb_src
item['thumb_alt']=thumb_alt
item['img_detail_src']=img_detail_src
item['path']=path
#yield类似于return,return后面的代码不执行,但是yield后面的会返回
yield item
with open(path+"/"+thumb_name,"wb") as f:
img_response = requests.get(thumb_src)
f.write(img_response.content)
with open(path+"/"+detail_name,"wb") as f:
img_response = requests.get(img_detail_src)
f.write(img_response.content)
"""
进程:进程之间数据是独立的
线程:生活在进程里面,一个进程里面会包含多个线程,一个进程 相当于一个人,一个线程相当于一个脑子,所以如果想让 你个进程同时做多件事,需要开多个线程.
默认线程只有一个,,叫做主线程;
一个线程每次只能做一件事,例如:迅雷能同时下载任 务量为1;多个线程可以"同时"做多件事,(同时代表感觉 是同时 ),例如:迅雷同时下载任务量为5,可以提高效率.
注意:线程不是越多越好,例如:火车站卖票,窗口越多,速度 越快,成本越高
注意:scrapy框架默认用的是多线程
注意:python没有多线程
协程:主要负责协助线程的资源切换
"""
"""
scrapy默认支持四种数据格式,分别是: .json .csv
操作:scrapy crawl 爬虫名称 -o 文件名
"""
基本步骤:
在利用scrapy框架进行爬虫时,若通过抓包工具获取的User-Agent数据中含有scrapy,证明是爬虫
scrapy的基本用法:
1. 通过命令创建项目
scrapy startproject 项目名称
2. 用pycharm打开项目
3. 通过命令创建爬虫
scrapy genspider 爬虫名称 域名
4. 配置settings(这三个是必须设置的)
robots_obey=False
Download_delay=0.5
Cookie_enable=False
5. 自定义UserAgentMiddleWare
可以直接粘现成的
(1.点开External Libraries-->site-packages-->scrapy-->downloadermiddlewares-->useragent全部复制,
2.粘贴到middlewares文件中,
3.在middlewares文件中需要导入包from fake_useragent import UserAgent
4.修改UserAgentMiddleWare类中的部分内容
)
或者自己通过研究源码实现
6. 开始解析数据
1) 先大致规划一下需要几个函数
2) 函数1跳转到函数2使用 yield scrapy.Request(url,callback,meta,dont_filter)
7. 将数据封装到items,记得yield item
8. 自定义pipelines将数据存储到数据库/文件中
注意:第五步的修改UserAgentMiddleWare类中的部分内容,具体修改如下:
class UserAgentMiddleware(object):
"""This middleware allows spiders to override the user_agent"""
def __init__(self):
self.user_agent = UserAgent()
@classmethod
#加载配置文件
def from_crawler(cls, crawler):
#不用读配置
o = cls()
# crawler.signals.connect(o.spider_opened, signal=signals.spider_opened)
return o
#该函数不能删,否则会报错
def spider_opened(self, spider):
# self.user_agent = getattr(spider, 'user_agent', self.user_agent)
pass
#请求处理
def process_request(self, request, spider):
if self.user_agent:
#b是什么二进制(不全,没听清)
request.headers.setdefault(
b'User-Agent',
self.user_agent.random)