目录
一、框架介绍
Scrapy是适用于Python的一个快速、高层次的屏幕抓取和web抓取框架,用于抓取web站点并从页面中提取结构化的数据。Scrapy用途广泛,可以用于数据挖掘、监测和自动化测试。Scrapy吸引人的地方在于它是一个框架,任何人都可以根据需求方便的修改。它也提供了多种类型爬虫的基类,如BaseSpider、sitemap爬虫等,最新版本又提供了web2.0爬虫的支持。
scrapy框架的工作流程如下流程图
- Scrapy Engine(引擎):负责Spider、ItemPipeline、Downloader、Scheduler中间的通讯,信号、数据传递等。
- Scheduler(调度器):它负责接受引擎发送过来的Request请求,并按照一定的方式进行整理排列,入队,当引擎需要时,交还给引擎。
- Downloader(下载器):负责下载Scrapy Engine(引擎)发送的所有Requests请求,并将其获取到的Responses交还给Scrapy Engine(引擎),由引擎交给Spider来处理。
- Spider(爬虫):它负责处理所有Responses,从中分析提取数据,获取Item字段需要的数据,并将需要跟进的URL提交给引擎,再次进入Scheduler(调度器)。
- Item Pipeline(管道):它负责处理Spider中获取到的Item,并进行进行后期处理(详细分析、过滤、存储等)的地方。
- Downloader Middlewares(下载中间件):一个可以自定义扩展下载功能的组件。
- Spider Middlewares(Spider中间件):一个可以自定扩展和操作引擎和Spider中间通信的功能组件。
以上内容来自百度搜索引擎,纯属为了扩展自己的知识面,没有故意侵权的想法
二、安装步骤
在terminal执行以下命令安装或者在pycharm的下载第三方模块的位置搜索安装也可以的,甚至可以源码安装
pip3.8 install scrapy
Mac或Linux系统直接执行以上命令就顺利安装,但是Windows有时会出现安装失败的情况,这时候,我可以以下步骤针对性的解决问题即可
第一步:pip3 install wheel #安装后,便支持通过wheel文件安装软件,wheel文件官网:https://www.lfd.uci.edu/~gohlke/pythonlibs
第二步:pip3 install lxml
第三步:pip3 install pyopenssl
第四步:下载并安装pywin32:https://sourceforge.net/projects/pywin32/files/pywin32/
第五步:下载twisted的wheel文件:http://www.lfd.uci.edu/~gohlke/pythonlibs/#twisted
第六步:执行pip3 install 下载目录\Twisted-17.9.0-cp36-cp36m-win_amd64.whl
第七步:pip3 install scrapy
三、创建项目
pycharm不支持在它可视化界面创建scrapy但是我们有cmd终端,我们在终端用命令创建项目再用pycharm打开即可
scrapy startproject myfirstscrapy # 第一步:创建项目 等同于 创建Django
cd myfirstscrapy # 第二步:CD到scrapy项目路径
scrapy genspider cnblogs www.cnblogs.com # 创建爬虫 等同于 创建app
在D盘根目录下就会有咱刚刚创建的scrapy项目咯
创建好了的项目可以在pycharm里打开进行开发
项目创建成功之后,命令方式运行
scrapy crawl cnblogs
用绿色三角形点击运行的话先建run.py 文件
然后呢,在该文件里写如下代码
from scrapy.cmdline import execute
execute(['scrapy', 'crawl', 'cnblogs','--nolog']) # --nolog指的是不输出日志
四、项目目录结构
五、项目配置
1. 基本配置
#项目名字,整个爬虫名字
BOT_NAME = "firstscrapy"
# 爬虫存放位置
SPIDER_MODULES = ["firstscrapy.spiders"]
NEWSPIDER_MODULE = "firstscrapy.spiders"
# 是否遵循爬虫协议,一般都设为False
ROBOTSTXT_OBEY = False
# 用户代理
USER_AGENT = "firstscrapy (+http://www.yourdomain.com)"
# 日志输出级别(当前是只输出报错信息)
LOG_LEVEL='ERROR'
# 默认请求头
DEFAULT_REQUEST_HEADERS = {
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'Accept-Language': 'en',
}
# 爬虫中间件
SPIDER_MIDDLEWARES = {
'cnblogs.middlewares.CnblogsSpiderMiddleware': 543,
}
# 下载中间件
DOWNLOADER_MIDDLEWARES = {
'cnblogs.middlewares.CnblogsDownloaderMiddleware': 543,
}
# 持久化配置
ITEM_PIPELINES = {
'cnblogs.pipelines.CnblogsPipeline': 300,
}
2. 提高爬虫效率的配置
#1 增加并发:默认16
默认scrapy开启的并发线程为32个,可以适当进行增加。在settings配置文件中修改
CONCURRENT_REQUESTS = 100
值为100,并发设置成了为100。
#2 降低日志级别:
在运行scrapy时,会有大量日志信息的输出,为了减少CPU的使用率。可以设置log输出信息为INFO或者ERROR即可。在配置文件中编写:
LOG_LEVEL = 'INFO'
# 3 禁止cookie:
如果不是真的需要cookie,则在scrapy爬取数据时可以禁止cookie从而减少CPU的使用率,提升爬取效率。在配置文件中编写:
COOKIES_ENABLED = False
# 4 禁止重试:
对失败的HTTP进行重新请求(重试)会减慢爬取速度,因此可以禁止重试。在配置文件中编写:
RETRY_ENABLED = False
# 5 减少下载超时:
如果对一个非常慢的链接进行爬取,减少下载超时可以能让卡住的链接快速被放弃,从而提升效率。在配置文件中进行编写:
DOWNLOAD_TIMEOUT = 10 超时时间为10s
六、解析数据
1. 解析方法
# response对象有css方法和xpath方法
css中写css选择器
xpath中写xpath选择
xpath取文本内容
'.//a[contains(@class,"link-title")]/text()'
xpath取属性
'.//a[contains(@class,"link-title")]/@href'
css取文本
'a.link-title::text'
css取属性
'img.image-scale::attr(src)'
.extract_first() 取一个
.extract() 取所有
2. 解析案例
用xpath解析cnblogs
import scrapy
class CnblogsSpider(scrapy.Spider):
name = "cnblogs"
allowed_domains = ["www.cnblogs.com"]
start_urls = ["https://www.cnblogs.com/"]
def parse(self, response):
"""css解析"""
article_list = response.xpath('//*[@id="post_list"]/article')
for article in article_list:
title = article.xpath('.//div/a/text()').extract_first()
author_img = article.xpath('.//div//img/@src').extract_first()
author_name = article.xpath('.//footer//span/text()').extract_first()
desc_old = article.xpath('.//p/text()').extract()
desc = desc_old[0].replace('\n', '').replace(' ', '')
if not desc:
desc = desc_old[1].replace('\n', '').replace(' ', '')
url = article.xpath('.//div/a/@href').extract_first()
info_demo = """
1.文章题目:%s
2.作者头像:%s
3.作者姓名:%s
4.文章简介:%s
5.文章地址:%s
"""
print(info_demo % (title, author_img, author_name,desc,url))
用css选择器解析cnblogs
import scrapy
class CnblogsSpider(scrapy.Spider):
name = "cnblogs"
allowed_domains = ["www.cnblogs.com"]
start_urls = ["https://www.cnblogs.com/"]
def parse(self, response):
"""css解析"""
article_list = response.css('article.post-item')
for article in article_list:
title = article.css('div.post-item-text>a::text').extract_first()
author_img = article.css('div.post-item-text img::attr(src)').extract_first()
author_name = article.css('footer span::text').extract_first()
desc_old = article.css('p.post-item-summary::text').extract()
desc = desc_old[0].replace('\n', '').replace(' ', '')
if not desc:
desc = desc_old[1].replace('\n', '').replace(' ', '')
url = article.css('div.post-item-text>a::attr(href)').extract_first()
info_demo = """
1.文章题目:%s
2.作者头像:%s
3.作者姓名:%s
4.文章简介:%s
5.文章地址:%s
"""
print(info_demo % (title, author_img, author_name,desc,url))
七、持久化方案
- items.py 写类
- 爬虫中,实例化得到对象(必须放在for内部),放到对象中数据,yield item对象
- pipline中写 类中3个方法
open_spider :打开资源
close_spider:关闭资源
process_item
- 配置文件中配置
第一步:在items.py中写一个类
import scrapy
class MyfirstscrapyItem(scrapy.Item):
title = scrapy.Field()
author_img = scrapy.Field()
author_name = scrapy.Field()
desc = scrapy.Field()
url = scrapy.Field()
content = scrapy.Field()
第二步:在piplines.py中写代码,写一个类:open_spide,close_spider,process_item
- open_spider:开启爬虫会触发
- close_spider:爬完会触发
- process_item:每次要保存一个对象会触发
import pymysql
class MyfirstscrapyMySqlPipeline:
def open_spider(self, spider):
self.conn = pymysql.connect(
user='root',
password="mire123",
host='127.0.0.1',
database='cnblogs',
port=3306,
)
self.cursor = self.conn.cursor()
def close_spider(self, spider):
self.cursor.close()
self.conn.close()
def process_item(self, item, spider): # article
sql = '''INSERT INTO article (title,author_img,author_name,`desc`,url,content) VALUES(%s,%s,%s,%s,%s,%s);'''
self.cursor.execute(sql,
args=[item['title'], item['author_img'], item['author_name'], item['desc'], item['url'],
item['content']
])
self.conn.commit()
return item
第三步:配置文件配置
ITEM_PIPELINES = {
"myfirstscrapy.pipelines.MyfirstscrapyMySqlPipeline": 300, # 数字越小优先级越大
}
第四步:在解析方法parse中yield item对象
import scrapy
from myfirstscrapy.items import MyfirstscrapyItem
from scrapy.http.request import Request
class CnblogsSpider(scrapy.Spider):
name = "cnblogs"
allowed_domains = ["www.cnblogs.com"]
start_urls = ["https://www.cnblogs.com/"]
# 解析出下一页地址,继续爬取
def parse(self, response):
article_list = response.xpath('//*[@id="post_list"]/article')
for article in article_list:
item = MyfirstscrapyItem()
title = article.xpath('.//div/a/text()').extract_first()
item['title'] = title
author_img = article.xpath('.//div//img/@src').extract_first()
item['author_img'] = author_img
author_name = article.xpath('.//footer//span/text()').extract_first()
item['author_name'] = author_name
desc_old = article.xpath('.//p/text()').extract()
desc = desc_old[0].replace('\n', '').replace(' ', '')
if not desc:
desc = desc_old[1].replace('\n', '').replace(' ', '')
item['desc'] = desc
url = article.xpath('.//div/a/@href').extract_first()
item['url'] = url
yield Request(url=url, callback=self.parser_detail, meta={'item': item}) # 爬完后执行的解析方法
next = 'https://www.cnblogs.com' + response.css('div.pager>a:last-child::attr(href)').extract_first()
yield Request(url=next, callback=self.parse)
# 解析详情的方法
def parser_detail(self, response):
content = response.css('#cnblogs_post_body').extract_first()
item = response.meta.get('item')
if content:
item['content'] = content
else:
item['content'] = '没查到'
yield item
八、在scrapy框架加proxy、cookie、header、selenium
class MyfirstscrapyDownloaderMiddleware:
@classmethod
def from_crawler(cls, crawler):
# This method is used by Scrapy to create your spiders.
s = cls()
crawler.signals.connect(s.spider_opened, signal=signals.spider_opened)
return s
## 1 加代理
def get_proxy(self):
import requests
res = requests.get('http://127.0.0.1:5010/get/').json()
if res.get('https'):
return 'https://' + res.get('proxy')
else:
return 'http://' + res.get('proxy')
# http://202.110.67.141:9091
def process_request(self, request, spider):
# 加代理,cookie,header,加入selenium
# 加代理
print(request)
request.meta['proxy'] = self.get_proxy()
return None
### 加cookie
def process_request(self, request, spider):
print(request.cookies)
request.cookies['name']='mire'
return None
# 加请求头
def process_request(self, request, spider):
print(request.headers)
request.headers['referer'] = '上一次访问的网址'
return None
# 动态生成User-agent使用
def process_request(self, request, spider):
# fake_useragent模块 第三方模块需要下载pip install fake_useragent
from fake_useragent import UserAgent
ua = UserAgent()
request.headers['User-Agent']=str(ua.random)
print(request.headers)
return None
def process_request(self, request, spider):
# 集成selenium
# 使用selenium打开request.url,加载完后,拿出当前页面中的数据,组装一个Resposne对象,返回即可
# spider 执行哪个爬虫,这个就是哪个爬虫对象
# print(spider)
# 爬取下一页这种地址---》用selenium,但是文章详情,就用原来的
if 'sitehome/p' in request.url:
spider.bro.get(request.url)
# print(spider.bro.page_source)
from scrapy.http.response.html import HtmlResponse
response = HtmlResponse(url=request.url, body=bytes(spider.bro.page_source, encoding='utf-8'))
return response
else:
return None
def process_response(self, request, response, spider):
# Called with the response returned from the downloader.
# Must either;
# - return a Response object
# - return a Request object
# - or raise IgnoreRequest
return response
def process_exception(self, request, exception, spider):
print('-----', request.url) # 遇到免费但用不了的代理时抛异常并返回request
return request
def spider_opened(self, spider):
spider.logger.info("Spider opened: %s" % spider.name)
tip:
加的代理是自己搭建的免费代理池
所以启动爬虫项目之前先启动代理池
获取随机免费代理,然后咱们得项目才能用的到
启动服务端和客户端的命令也贴一下这里吧
# 如果已经具备运行条件, 可用通过proxyPool.py启动。
# 程序分为: schedule 调度程序 和 server Api服务
# 启动调度程序
python proxyPool.py schedule
# 启动webApi服务
python proxyPool.py server
标签:框架,self,request,spider,item,scrapy,article
From: https://www.cnblogs.com/almira998/p/17269161.html