Scrapy初步
Scrapy基于Twisted设计实现,Twisted的特殊特性是以事件驱动,并且对于异步的支持性很好,集成了高性能的异步下载,队列,分布式,持久化等。
Scrapy的安装
在Linux中可以直接在命令行中输入:pip install scrapy
在windows中:
- pip3 install wheel
- 下载twisted,http:
/
/
www.lfd.uci.edu
/
~gohlke
/
pythonlibs
/
#twisted
- 下载的Twisted一定要和自己当前python解释器的版本相匹配,不然不会报这个错误:
Twisted-18.9.0-cp37-cp37m-win_amd64.whl is not a supported wheel on this platform.
- 进入下载目录,执行 pip3 install Twisted‑
17.1
.
0
‑cp35‑cp35m‑win_amd64.whl
- pip3 install pywin32
- pip3 install scrapy
Scrapy的目录结构
使用 scrapy startproject projectname 启动项目。
- scrapy.cfg scrapy项目的基础配置
- items.py 设置数据存储模板,用于结构化数据,如Django的Model
- middlewares.py 自己定义的中间件
- piplines 数据的持久化处理
- settings.py 配置文件,如:递归的层数、并发数、延迟下载等
- spiders 爬虫目录,创建文件,编写解析规则等
创建爬虫应用程序:
- 进入项目目录
- scrapy genspider 应用名称 爬取网页的起始url (例如: scrapy genspider test_1 www.baidu.com)
- 会出现一个appname.py的文件,文件内容如下
import scrapy class Test1Spider(scrapy.Spider): name = 'test_1' #应用名 allowed_domains = ['www.baidu.com'] #允许爬取的域名,如果非该域名的则跳过 start_urls = ['http://www.baidu.com/'] #起始爬取的url #访问起始url并获取结果后的回调函数,该函数的response参数就是向起始的url发送请求后,获取的相应对象,
该函数的返回值必须为可迭代对象获知NULL
def parse(self, response): pass #response.text 获取字符串类型的相应内容
#reponse.body 获取字节类型的相应内容
程序执行:
- scrapy crawl 爬虫名称
- scrapy crawl --nolog #不显示执行的日志信息
案例一
修改settings.py文件
USER_AGENT="Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36 QIHU 360EE" ROBOTSTXT_OBEY=False #忽略君子协议
打开sprider文件
import scrapy
class QiuSprider(scrapy.Sprider):
name="qiusp"
allowed_domains=['https://www.qiushibaike.com/']
start_urls=['https://www.qiushibaike.com/']
def parse(self,response):
#xpath为response函数的方法
odiv=response.xpath('//div[@id="content-left"]/div')
content_list=[] #存储解析数据
for div in odiv:
#xpath函数返回列表,列表中的数据为selector类型,需要调用extract()函数取出数据
author = div.xpath('.//div[@class="author clearfix"]/a/h2/text()')[0].extract()
content=div.xpath('.//div[@class="content"]/span/text()')[0].extract()
#将解析内容封装到字典中
dic={ '作者':author, '内容':content }
#将数据存到content_list中
content_list.append(dic)
return content_list
案例二
spider
import scrapy from bossPro.items import BossproItem class BossSpider(scrapy.Spider): name = 'boss' # allowed_domains = ['www.xxx.com'] start_urls = ['https://www.zhipin.com/job_detail/?query=python%E7%88%AC%E8%99%AB&scity=101010100&industry=&position='] url = 'https://www.zhipin.com/c101010100/?query=python爬虫&page=%d&ka=page-2' page = 1 #解析+管道持久化存储 def parse(self, response): li_list = response.xpath('//div[@class="job-list"]/ul/li') for li in li_list: job_name = li.xpath('.//div[@class="info-primary"]/h3/a/div/text()').extract_first() salary = li.xpath('.//div[@class="info-primary"]/h3/a/span/text()').extract_first() company = li.xpath('.//div[@class="company-text"]/h3/a/text()').extract_first() #实例化一个item对象 item = BossproItem() #将解析到的数据全部封装到item对象中 item['job_name'] = job_name item['salary'] = salary item['company'] = company #将item提交给管道 yield item if self.page <= 3: print('if 执行!!!') self.page += 1 new_url = format(self.url%self.page) print(new_url) #手动请求发送 yield scrapy.Request(url=new_url,callback=self.parse)
items.py
items.py存放的是我们要爬取数据的字段信息,我们要爬取的是工作名,薪资,公司名。
# Define here the models for your scraped items # # See documentation in: # https://doc.scrapy.org/en/latest/topics/items.html import scrapy class BossproItem(scrapy.Item): # define the fields for your item here like: job_name = scrapy.Field() salary = scrapy.Field() company = scrapy.Field()
pipelines.py
pipelines.py主要是对spiders中爬虫返回的数据进行处理的,在这里我们让其写入redis和写入文件,
pipeline可以随意定义,但是它是有顺序的,所以我们要在settings.py设置权重,数字越小,优先级越高。
# Define your item pipelines here # # Don't forget to add your pipeline to the ITEM_PIPELINES setting # See: https://doc.scrapy.org/en/latest/topics/item-pipeline.html from redis import Redis class BossproPipeline(object): fp = None def open_spider(self, spider): print('开始爬虫......') self.fp = open('./boss.txt','w',encoding='utf-8') def close_spider(self, spider): print('结束爬虫......') self.fp.close() #爬虫文件每向管道提交一次item,则该方法就会被调用一次. #参数:item 就是管道接收到的item类型对象 def process_item(self, item, spider): #print(item) self.fp.write(item['job_name']+':'+item['salary']+':'+item['company']+' ') return item #返回给下一个即将被执行的管道类 class redisPileLine(object): conn = None def open_spider(self,spider): self.conn = Redis(host='127.0.0.1',port=6379) print(self.conn) def process_item(self, item, spider): # print(item) dic = { 'name':item['job_name'], 'salary':item['salary'], 'company':item['company'] } self.conn.lpush('boss',dic)
settings.py
USER_AGENT="Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36 QIHU 360EE"
ROBOTSTXT_OBEY=False #忽略君子协议
ITEM_PIPELINES = { 'bossPro.pipelines.BossproPipeline': 300, 'bossPro.pipelines.redisPileLine': 301, }