文章目录
前言
- 什么是框架?
就是一个集成了很多功能并且具有很强通用性的一个项目模板。
- 如何学习框架?
专门学习框架封装的各种功能的详细用法。
- 什么是scrapy?
爬虫中封装好的一个明星框架。
功能:
- 高性能的持久化操作
- 异步的数据下载操作
- 高性能的数据解析操作
- 分布式操作
一、scrapy框架的基本使用
- 环境安装
linux和mac操作系统:pip install scrapy
windows系统:
pip install wheel
下载twisted,下载地址为http://www.lfd.uci.edu/~gohlke/pythonlibs/#twisted
安装twisted:pip install Twisted‑17.1.0‑cp36‑cp36m‑win_amd64.whl
pip install pywin32
pip install scrapy
测试:在终端里录入scrapy指令,没有报错即表示安装成功!
1.1 windows下安装scrapy
- 安装wheel
pip install wheel
- 下载twisted
- 安装pywin32
pip install pywin32
- 安装scrapy
pip install scrapy
一开始安装失败,系统提示让我更新pip,更新pip后从新安装成功。
更新pip的命令:
python -m pip install --upgrade pip
1.2 scrapy的基本使用
- 步骤流程
- 通过终端指令创建一个工程:
scrapy startproject xxxPro
- cd xxxPro
- 在spiders子目录中创建一个爬虫文件:
scrapy genspider spiderName 域名
- 执行工程:
scrapy crawl spiderName
【不显示日志:scrapy crawl spiderName --nolog
】
- 终端命令在VScode中演示
spiders文件里一定要放一个.py的爬虫文件
- 讲解scrapy创建的spiderName爬虫文件
import scrapy
class FirstSpider(scrapy.Spider):
# 爬虫文件的名称 :就是爬虫源文件的唯一标识,即不能够重复
name = 'first'
# 允许的域名:用来限定start_urls列表中哪些url可以进行请求发送,一般该字段不用
# allowed_domains = ['www.xxx.com']
# 起使的url列表:该列表中存放的url会被scrapy自动进行请求的发送,可以有多个url
start_urls = ['https://www.baidu.com/','https://www.sogou.com/']
# 用于数据解析 response参数表示的就是请求成功之后对应的响应对象
# parse方法调用的次数由start_urls中url的个数决定的
def parse(self, response):
pass # 将print(response代替pass进行验证)
发现上述输出并没有有关start_urls中url的相关内容,
修改settings.py
中ROBOTSTXT_OBEY = False
不显示日志:
scrapy crawl spiderName --nolog
在settings.py中加入LOG_LEVEL ='ERROR'
,显示指定类型的日志信息
- 对比信息
- 使用上述scrapy框架
- 使用requests模块
import requests
if __name__ == "__main__":
# 1. 指定url
url = "https://www.sogo.com/"
# 2. 发起请求
response = requests.get(url=url)
# get方法灰返回一个响应对象
# 3. 获取相应数据 .text返回的是字符串形式的响应数据
page_text = response
print(page_text)
二、scrapy数据解析
scrapy框架的基本流程操作完毕后,一定要对settings.py文件进行如下操作:
- 修改USER_AGENT
- ROBOTSTXT_OBEY = False
- LOG_LEVEL = ‘ERROR’
- 爬取xx百科中的段子⭐⭐
import scrapy
class QiubaiSpider(scrapy.Spider):
name = 'qiubai'
# allowed_domains = ['www.xxx.com']
# 爬取糗事百科中段子的作者和内容
start_urls = ['https://www.qiushibaike.com/text/']
# 数据解析
def parse(self, response):
# 解析:作者的名称+段子内容
div_list = response.xpath('//div[contains(@class,"col1")]/div')
# print('div_list:',div_list)
for div in div_list:
# 所有的xpath返回的都是列表,但是列表元素一定是Selector类型的对象
# extract()可以将Selector类型的对象中的字符串提取出来
# author = div.xpath('./div[1]/a[2]/h2/text()')[0].extract()
# 如果保证返回的列表元素只有一个列表元素是可以使用extract_first()
author = div.xpath('./div[1]/a[2]/h2/text()').extract_first()
# 列表调用extract()表示将列表中每一个Selector对象中的字符串提取出来,并返回列表
# 即列表调用extract()后返回还是列表
content = div.xpath('./a[1]/div/span//text()').extract() # 由于有的标签中含有<br>标签,取所有内容用//
content = ''.join(content)# 列表转换为字符串
print(author, content)
break # 只输出一次用来查看
- 问题总结
- 遇到class中含有多个属性值
extract 和 extract_first()
import scrapy
class SecondSpider(scrapy.Spider):
name = "second"
# allowed_domains = ["www.xxx.com"]
start_urls = ['https://duanzixing.com/']
def parse(self, response):
articles = response.xpath('/html/body/section/div/div[1]/article')
print('直接查看 输出是 [<Selector ... >] [<Selector ... >] ')
for article in articles:
title = article.xpath('./header/h2/a/text()')
content = article.xpath('./p[2]/text()')
print(title,content)
break
print('*'*100)
print('加上[0] 输出是 <Selector ... > <Selector ... > ')
for article in articles:
title = article.xpath('./header/h2/a/text()')[0]
content = article.xpath('./p[2]/text()')[0]
print(title,content)
break
print('*'*100)
print('加上[0]extract() 输出是 Selector 中的内容 ')
for article in articles:
title = article.xpath('./header/h2/a/text()')[0].extract()
content = article.xpath('./p[2]/text()')[0].extract()
print(title,content)
break
print('*'*100)
print("加上extract() 输出是 ['内容']['内容'] ")
for article in articles:
title = article.xpath('./header/h2/a/text()').extract()
content = article.xpath('./p[2]/text()').extract()
print(title,content)
break
print('*'*100)
print("extract_first() 输出是 '内容' '内容' ")
for article in articles:
title = article.xpath('./header/h2/a/text()').extract_first()
content = article.xpath('./p[2]/text()').extract_first()
print(title,content)
break
直接查看 输出是 [<Selector ... >] [<Selector ... >]
[<Selector xpath='./header/h2/a/text()' data='人死为鬼, 鬼死为聻, 聻死为希, 希死为夷....'>] [<Selector xpath='./p[2]/text()' data='人死为鬼,鬼死为聻,聻死为希,希死为夷,夷死为魁,魁死为魆,魆死为
魉,魉死...'>]
****************************************************************************************************
加上[0] 输出是 <Selector ... > <Selector ... >
<Selector xpath='./header/h2/a/text()' data='人死为鬼, 鬼死为聻, 聻死为希, 希死为夷....'> <Selector xpath='./p[2]/text()' data='人死为鬼,鬼死为聻,聻死为希,希死为夷,夷死为魁,魁死为魆,魆死为魉,魉死...'>
****************************************************************************************************
加上[0]extract() 输出是 Selector 中的内容
人死为鬼, 鬼死为聻, 聻死为希, 希死为夷.... 人死为鬼,鬼死为聻,聻死为希,希死为夷,夷死为魁,魁死为魆,魆死为魉,魉死无形。无形生道,道生一,一生二,二生三,三生万物。水清则浅,水绿则深,水黑则深,
鳝大成蛇,蛇大成蟒,蟒大成蛟,蛟大成龙,龙大成王,王中王,火腿...
****************************************************************************************************
加上extract() 输出是 ['内容']['内容']
['人死为鬼, 鬼死为聻, 聻死为希, 希死为夷....'] ['人死为鬼,鬼死为聻,聻死为希,希死为夷,夷死为魁,魁死为魆,魆死为魉,魉死无形。无形生道,道生一,一生二,二生三,三生万物。水清则浅,水绿则深,水黑
则深,鳝大成蛇,蛇大成蟒,蟒大成蛟,蛟大成龙,龙大成王,王中王,火腿...']
****************************************************************************************************
extract_first() 输出是 '内容' '内容'
人死为鬼, 鬼死为聻, 聻死为希, 希死为夷.... 人死为鬼,鬼死为聻,聻死为希,希死为夷,夷死为魁,魁死为魆,魆死为魉,魉死无形。无形生道,道生一,一生二,二生三,三生万物。水清则浅,水绿则深,水黑则深, 鳝大成蛇,蛇大成蟒,蟒大成蛟,蛟大成龙,龙大成王,王中王,火腿...
三、scrapy持久化存储
- 基于终端指令
要求:只可以将parse方法的返回值存储到本地的文本文件中【往数据库中存储是不行的】- 基于管道⭐⭐
- 数据解析
- 在Item类中定义相关的属性
- 将解析的数据封装到item类型的对象【使用items.py文件】
- 将Item类型对象提交给管道进行持久化存储操作
- 在管道类的process_item中呀将其接收到的item对象中存储的数据进行持久化存储操作【使用pipelines.py】
- 在配置文件中开启管道【scrapy默认情况是没有开启管道功能需要手动开启】
3.1 基于终端指令
例如第二章中爬取xx百科中的段子进行存储的代码如下:
import scrapy
class QiubaiSpider(scrapy.Spider):
name = 'qiubai'
# allowed_domains = ['www.xxx.com']
# 爬取糗事百科中段子的作者和内容
start_urls = ['https://www.qiushibaike.com/text/']
# 数据解析
def parse(self, response):
div_list = response.xpath('//div[contains(@class,"col1")]/div')
all_data = [] # 存储所有数据
# print('div_list:',div_list)
for div in div_list:
# 所有的xpath返回的都是列表,但是列表元素一定是Selector类型的对象
# extract()可以将Selector类型的对象中的字符串提取出来
# author = div.xpath('./div[1]/a[2]/h2/text()')[0].extract()
# 如果保证返回的列表元素只有一个列表元素是可以使用extract_first()
author = div.xpath('./div[1]/a[2]/h2/text()').extract_first()
# 列表调用extract()表示将列表中每一个Selector对象中的字符串提取出来,并返回列表
# 即列表调用extract()后返回还是列表