爬虫之Scrapy和分页
下一页和详情页的处理
xpath提取时
注意:
结合网页源代码一起查找 不用框架的爬取
获取下一页
自带href属性
1)首页有下一页
next_url = element.xpath('.//a[text()="下一页"]/@href')
next_url = self.temp_url + next_url[0] if len(next_url) > 0 else None 2)详情页有下一页
next_url = element.xpath('.//a[text()="下一页"]/@href')
next_url = self.temp_url + next_url[0] if len(next_url) > 0 else None
# print(next_url)
if (next_url is not None) and count <= self.max_detail_page:
image_list = self.get_detail_list(next_url,image_list,count)
return image_list image_list = [requests.utils.unquote(i).spilt("src=")[-1] for i in image_list]
return image_list 不带href属性
用selenium 进入详情页
还有iframe框架的
用selenium 只有普通标签堆叠的
def get_detail_list(self,detail_url,image_list,count):
""" 获取详情页的数据 """
detail_html_str = self.parse_url(detail_url)
element = etree.HTML(detail_html_str)
# image_list += element.xpath('//div[@class="i"]/a/@href')
image_list += element.xpath("//img[@class='BDE_Image']/@src") # 获取详情页中的下一页的数据
next_url = element.xpath('.//a[text()="下一页"]/@href')
next_url = self.temp_url + next_url[0] if len(next_url) > 0 else None
# print(next_url)
if (next_url is not None) and count <= self.max_detail_page:
image_list = self.get_detail_list(next_url,image_list,count)
return image_list image_list = [requests.utils.unquote(i).spilt("src=")[-1] for i in image_list] return image_list scrapy框架
需要装模块
1.先装twisted再装scrapy
2.pip install pywin32
什么是scrapy
Scrapy是一个为了爬取网站数据,提取结构性数据而编写的应用框架,我们只需要实现少量的代码就能够快速的抓取想要的数据
Scrapy 使用了Twisted['twɪstɪd]异步网络框架,可以加快我们的下载速度 异步和非阻塞的区别
异步:调用在发出之后,这个调用就直接返回,不管有无结果
非阻塞:关注的是程序在等待调用结果(消息,返回值)时的状态,指在不能立刻得到结果之前, 该调用不会阻塞当前线程 scrapy的流程
其流程可以描述如下:
调度器把requests-->引擎-->下载中间件--->下载器
下载器发送请求,获取响应---->下载中间件---->引擎--->爬虫中间件--->爬虫
爬虫提取url地址,组装成request对象---->爬虫中间件--->引擎--->调度器
爬虫提取数据--->引擎--->管道
管道进行数据的处理和保存
注意:
图中绿色线条的表示数据的传递
注意图中中间件的位置,决定了其作用
注意其中引擎的位置,所有的模块之前相互独立,只和引擎进行交互 # 创建爬虫
命令:scrapy startproject +<项目名字>
scrapy startproject sunshine # 生成一个爬虫
命令:scrapy genspider +<爬虫名字> + <允许爬取的域名>
cd mySpider
scrapy genspider shine wz.sun0769.com # 执行爬虫
scrapy crawl shine spider模块
class ShineSpider(scrapy.Spider):
name = 'shine'
allowed_domains = ['wz.sun0769.com']
start_urls = ['http://wz.sun0769.com/index.php/question/questionType?type=4&page=0'] def parse(self,response):
td_list = response.xpath('//table//tr/td/table//tr')
for td in td_list:
items = {}
items["id_num"] = td.xpath('./td[1]/text()').extract_first()
items["status"] = td.xpath('./td[3]/span/text()').extract()
items["web_firends"] = td.xpath('./td[4]/text()').extract_first()
items["pubdate"] = td.xpath('./td[5]/text()').extract_first()
items["title"] = td.xpath('./td[2]/a/text()').extract()
items["href"] = td.xpath('./td[2]/a[2]/@href').extract_first()
yield scrapy.Request(
items["href"],
callback=self.parse_detail,
meta={"a":items}
) next_page_url = response.xpath("//a[text()='>']/@href").extract_first()
if next_page_url is not None:
# 构造请求
print(22)
yield scrapy.Request(next_page_url, callback=self.parse) def parse_detail(self,response):
items = response.meta["a"]
items["img"] = "http://wz.sun0769.com/" +
str(response.xpath('//div[@class="wzy1"]//div[@class="textpic"]/img/@src').extract_first())
items["content"] = [i.strip() for i in (response.xpath('//div[@class="wzy1"]//tr[1]/td//text()').extract())] yield items 注意:
1)response.xpath方法的返回结果是一个类似list的类型,其中包含的是selector对象,操作和列表一样,但是有一些额外的方法
2)extract() 返回一个包含有字符串的列表
3)extract_first() 返回列表中的第一个字符串,列表为空返回None
4)spider中的parse方法必须有
5)需要抓取的url地址必须属于allowed_domains,但是start_urls中的url地址没有这个限制
6)启动爬虫的时候注意启动的位置,是在项目路径下启动 为什么要使用yield?
让整个函数变成一个生成器,有什么好处呢?
遍历这个函数的返回值的时候,挨个把数据读到内存,不会造成内存的瞬间占用过高
注意
yield能够传递的对象只能是:BaseItem,Request,dict,None # 构造下一页的地址
# //div@class="pagenav"]//a[@class="noactive"]/@href
next_page_url = response.xpath('//a[@id="next"]/@href').extract_first()
# print(next_page_url)
# print(11)
# 判断是不是下一页
if next_page_url != "javascript:;":
print(22)
1)手动拼接url
next_page_url = "https://hr.tencent.com/" + next_page_url
2)利用urllib下的parse来拼接
next_page_url = parse.urljoin(response.url,next_page_url)
yield scrapy.Request(next_page_url,callback=self.parse)
# 根据response的地址,对next_page_url的url进行拼接,构造请求
3)yield response.follow(next_page_url,callback=self.parse) pipelines模块
from pymongo import MongoClient
client = MongoClient("localhost",27017)
collection = client["sunshine"]["shine"] class SunshinePipeline(object):
def process_item(self, item, spider):
print(item)
# 判断当前的爬虫
if spider.name == "shine":
# 保存在数据库中
collection.insert_one(item)
return item 管道中的open_spider和close_spider 的方法
在管道中,除了必须定义process_item之外,还可以定义两个方法:
open_spider(spider):能够在爬虫开启的时候执行一次
close_spider(spider):能够在爬虫关闭的时候执行一次
所以,上述方法经常用于爬虫和数据库的交互,在爬虫开启的时候建立和数据库的连接,
在爬虫关闭的时候断开和数据库的连接 settings模块
需要在settings开启设置
pipeline在settings中能够开启多个,为什么需要开启多个? 不同的pipeline可以处理不同爬虫的数据
不同的pipeline能够进行不同的数据处理的操作,比如一个进行数据清洗,一个进行数据的保存
pipeline使用注意点:
1)使用之前需要在settings中开启
2)pipeline在setting中键表示位置(即pipeline在项目中的位置可以自定义),值表示距离引擎的远近,越近数据会越先经过
3)有多个pipeline的时候,process_item的方法必须returnitem,否则后一个pipeline取到的数据为None值
4)pipeline中process_item的方法必须有,否则item没有办法接受和处理
5)process_item方法接受item和spider,其中spider表示当前传递item过来的spider 输出日志LOG的设置
为了让我们自己希望输出到终端的内容能容易看一些,我们可以在setting中设置log级别在setting中添加一行(全部大写):LOG_LEVEL = "WARNING"
默认终端显示的是debug级别的log信息 scrapy.Request的更多参数
scrapy.Request(url[,callback,method="GET",headers,body,cookies,meta,dont_filter=False])
注意:
括号中的参数为可选参数
callback:表示当前的url的响应交给哪个函数去处理
meta:实现数据在不同的解析函数中传递,meta默认带有部分数据,比如下载延迟,请求深度等
dont_filter:默认会过滤请求的url地址,即请求过的url地址不会继续被请求,对需要重复请求的url
地址可以把它设置为Ture,比如贴吧的翻页请求,页面的数据总是在变化;start_urls中的地址会被反复请求,否则程序不会启动 scrapy 的数据传递的流程
- 调度器 request对象---》引擎---》下载器中间件---》下载器
- 下载器发送请求,获取response---》下载器中间件--》引擎---》爬虫中间件---》爬虫
- 怕从--》提取url,组成一个request对象---》爬虫中间件---》引擎---》调取器
- 爬虫---》提取数据---》引擎--》管道
- 管道实现数据的处理和保存 scrapy的项目流程
- 创建项目 :scrapy startproject 项目名
- 创建爬虫:cd 项目名下 ,scrapy genspider 爬虫名 allowed_domains
- 完善爬虫 :提取数据,提取url地址组成request
- 完善管道:数据的处理和保存 scrapy如何构造请求
- scrapy.Request(url,callback,meta,dont_filter)
- url:详情页,下一页的url
- callback:url地址响应的处理函数
- meta:在不同的函数中传递数据
- dont_filter :默认值false,过滤请求,请求过的不会再被请求,为True,表示会被继续请求
- yield scrapy.Request(url,callback,meta,dont_filter) scrapy的Item如何使用
#定义
class Item(scrapy.Item):
name = scrapy.Field() #使用
导入。使用name字典 scrapy中parse函数是做什么的
处理start_urls中的url地址的响应 设置scrapy的debug信息 scrapy shell的使用
scrapy shell是scrapy提供的一个终端工具,能够通过它查看scrapy中对象的属性和方法,以及测试xpath
使用方法:scrapy shell http://www.itcast.cn/channel/teacher.shtml
在终端输入上述命令后,能够进入python的交互式终端
小知识点:
1)response.url:当前响应的url地址
2)response.request.url:当前响应对应的请求的url地址
3)response.headers:响应头
4)response.body:响应体,也就是html代码,默认是byte类型
5)response.requests.headers:当前响应的请求头 认识scrapy中的setting文件
为什么项目中需要配置文件
在配置文件中存放一些公共变量,在后续的项目中便便修改,注意其中的变量名一般全部大写配置文件中的变量使用方法 导入即可使用
settings.py中的重点字段和内涵
USER_AGENT:设置UA
ROBOTSTXT_OBEY:是否遵守robots协议,默认是遵守
CONCURRENT_REQUESTS:设置并发请求的数量,默认是16个
DOWNLOAD_DELAY:下载延迟,默认无延迟
COOKIES_ENABLED:是否开启cookie,即每次请求带上前一次的cookie,默认是开启的
DEFAULT_REQUEST_HEADERS:设置默认请求头
SPIDER_MIDDLEWARES:爬虫中间件,设置过程和管道相同
DOWNLOADER_MIDDLEWARES:下载中间件 crawlspider的使用
crawlspider是什么
回顾之前的代码中,我们有很大一部分时间在寻找下一页的url地址或者是内容的url地址上面,这个过程能更简单一些么?
思路:
从response中提取所有的满足规则的url地址,自动的构造自己requests请求,发送给引擎对应的crawlspider就可以实现上述需求,
匹配满足条件的url地址,才发送给引擎,同时能够指定callback函数 认识crawlspider爬虫
1)创建crawlspdier爬虫的命令
scrapy genspider –t crawl itcast itcast.cn 2)观察爬虫内的默认内容
spider中默认生成的内容如下,其中重点在rules中
rules是一个元组或者是列表,包含的是Rule对象
Rule表示规则,其中包含LinkExtractor,callback和follow
LinkExtractor:连接提取器,可以通过正则或者是xpath来进行url地址的匹配
callback:表示经过连接提取器提取出来的url地址响应的回调函数,可以没有,没有表示响应不会进行回调函数的处理
follow:表示进过连接提取器提取的url地址对应的响应是否还会继续被rules中的规则进行提取,True表示会,Flase表示不会 class Itcast1Spider(CrawlSpider):
name = 'itcast1'
allowed_domains = ['itcast.cn']
start_urls = ['http://www.itcast.cn/channel/teacher.shtml#ajavaee'] rules = (
Rule(LinkExtractor(allow=r'Items/'), callback='parse_item', follow=True),
) # 名字很重要,主要用来提取url
def parse_item(self, response):
# 用来存放数据
i = {}
#使用xpath进行数据的提取或者url地址的提取
return i crawlspider使用的注意点
1)CrawlSpider不在是以parse为名字的数据提取方法,这个方法被CrawlSpider用来提取基础的url等功能
2)一个Rule可以接受多个参数,首先第一个是包含LinkExtractor的对象,常用的还有callback和follow
3)不指定callback函数请求的情况下,follow如果为True,满足rule的url还会继续被请求如果多个Rule满足同一个url,会从rules中选择第一个满足的操作 crawlspider的知识点
1)可以根据正则的匹配下一页和详情页的url不在需要我们自己去找,只要满足这类规则,他就会自动去帮我们找
2)LinkExtractor中的更多参数
allow:满足括号中的"正则表达式" 的URL一定会被提取,如果为空,则全部匹配
deny: 满足括号中的"正则表达式" 的URL一定不会被提取
allowed_domains: 会被提取连接的domains
deny_domains: 一定不会被提取连接的domains
restrict_xpaths: 使用xpath表达式,和allow共同作用过滤链接,及xpath满足范围内的url会被提取
3)Spider_Rule常见参数
link_extractor: 是一个LinkExtractor对象,用于定义需要提取的连接
callback:从link_extractor中获取url连接时,用于执行该url的回调函数
follow: 是一个boolean值,指定了从response中获取URL时是否需要跟进,默认值为True
process_links: 指定spiders中那个函数需要被调用,从link_extractor中获取连接列表时,将会调用该函数,该方法主要用来过滤url,
process_request:指定spider中那个函数将会被调用,该规则提取到每个requests时,都会调用该函数,用来 过滤request scrapy中下载中间件的使用
使用方法
编写一个Downloader Middlewares和我们编写一个pipeline一样,定义一个类,然后在setting中开启 Downloader Middlewares默认的方法
process_request(self, request, spider): 当每个request通过下载中间件时,该方法被调用。
返回None值:继续请求
返回Response对象:不在请求,把response返回给引擎
返回Request对象:把request对象交给调度器进行后续的请求
process_response(self, request, response, spider):
当下载器完成http请求,传递响应给引擎的时候调用
返回Resposne:交给process_response来处理
返回Request对象:交给调取器继续请求
定义实现随机User-Agent的下载中间件
# 手动创建池子
class UserAgentMiddleware(object):
def process_request(self,request,spider):
agent = random.choice(agents)
request.headers['User-Agent'] = agent
定义实现随机使用代理的下载中间件
class ProxyMiddleware(object):
def process_request(self,request,spider):
proxy = random.choice(proxies)
request.meta['proxy'] = proxy 使用scrapy进行模拟登陆
requests是如何模拟登陆的?
直接携带cookies请求页面,找接口发送post请求存储cookie
selenium是如何模拟登陆的?
找到对应的input标签,输入文字点击登录
scrapy来说,有两个方法模拟登陆:
1)直接携带cookie
2)找到发送post请求的url地址,带上信息,发送请求 scrapy携带cookie进行模拟登陆
携带cookie进行模拟登陆应用场景
cookie过期时间很长,常见于一些不规范的网站
能在cookie过期之前把搜有的数据拿到
配合其他程序使用,比如其使用selenium把登陆之后的cookie获取到保存到本地,scrapy
发送请求之前先读取本地cookie
scrapy的start_requests方法的学习 scrapy中start_url是通过start_requests来进行处理的,其实现代码如下 def start_requests(self):
cls = self.__class__
if method_is_overridden(cls, Spider, 'make_requests_from_url'):
warnings.warn(
"Spider.make_requests_from_url method is deprecated; it "
"won't be called in future Scrapy releases. Please "
"override Spider.start_requests method instead (see %s.%s)." % (
cls.__module__, cls.__name__
),
)
for url in self.start_urls:
yield self.make_requests_from_url(url)
else:
for url in self.start_urls:
yield Request(url, dont_filter=True) 所以对应的,如果start_url地址中的url是需要登录后才能访问的url地址,则需要重写start_request方法并在其中手动添加上cookie scrapy发送post请求 1)构造参数:
#spider/github.py
# -*- coding: utf-8 -*-
import scrapy
import re class GithubSpider(scrapy.Spider):
name = 'github'
allowed_domains = ['github.com']
start_urls = ['https://github.com/login'] def parse(self, response):
authenticity_token = response.xpath("//input[@name='authenticity_token']/@value").extract_first()
utf8 = response.xpath("//input[@name='utf8']/@value").extract_first()
commit = response.xpath("//input[@name='commit']/@value").extract_first() yield scrapy.FormRequest(
"https://github.com/session",
formdata={
"authenticity_token":authenticity_token,
"utf8":utf8,
"commit":commit,
"login":"noobpythoner",
"password":"***"
},
callback=self.parse_login
) def parse_login(self,response):
ret = re.findall("noobpythoner",response.text,re.I)
print(ret) 2)scrapy进行表单提交
def parse(self, response):
yield scrapy.FormRequest.from_response(
response,# 自动的从中寻找action对应的url地址
formdata={
"login":"noobpythoner",
"password":"***"
},
callback = self.parse_login
)
Scrapy_redis使用
scrapy_redis实现增量式爬虫:
Scrapy_redis在scrapy的基础上实现了更多,更强大的功能,具体体现在:
1)请求对象的持久化
2)去重的持久化
3)和实现分布式
爬虫之Scrapy和分页的更多相关文章
- Python 爬虫七 Scrapy
Scrapy Scrapy是一个为了爬取网站数据,提取结构性数据而编写的应用框架. 其可以应用在数据挖掘,信息处理或存储历史数据等一系列的程序中.其最初是为了页面抓取 (更确切来说, 网络抓取 )所设 ...
- 网络爬虫值scrapy框架基础
简介 Scrapy是一个高级的Python爬虫框架,它不仅包含了爬虫的特性,还可以方便的将爬虫数据保存到csv.json等文件中. 首先我们安装Scrapy. 其可以应用在数据挖掘,信息处理或存储历史 ...
- Python逆向爬虫之scrapy框架,非常详细
爬虫系列目录 目录 Python逆向爬虫之scrapy框架,非常详细 一.爬虫入门 1.1 定义需求 1.2 需求分析 1.2.1 下载某个页面上所有的图片 1.2.2 分页 1.2.3 进行下载图片 ...
- 教你分分钟学会用python爬虫框架Scrapy爬取心目中的女神
本博文将带领你从入门到精通爬虫框架Scrapy,最终具备爬取任何网页的数据的能力.本文以校花网为例进行爬取,校花网:http://www.xiaohuar.com/,让你体验爬取校花的成就感. Scr ...
- 爬虫之scrapy框架
解析 Scrapy解释 Scrapy是一个为了爬取网站数据,提取结构性数据而编写的应用框架. 其可以应用在数据挖掘,信息处理或存储历史数据等一系列的程序中.其最初是为了页面抓取 (更确切来说, 网络抓 ...
- 【转载】教你分分钟学会用python爬虫框架Scrapy爬取心目中的女神
原文:教你分分钟学会用python爬虫框架Scrapy爬取心目中的女神 本博文将带领你从入门到精通爬虫框架Scrapy,最终具备爬取任何网页的数据的能力.本文以校花网为例进行爬取,校花网:http:/ ...
- 爬虫入门scrapy
Python之路[第十九篇]:爬虫 网络爬虫(又被称为网页蜘蛛,网络机器人,在FOAF社区中间,更经常的称为网页追逐者),是一种按照一定的规则,自动地抓取万维网信息的程序或者脚本.另外一些不常使用 ...
- 爬虫框架Scrapy
前面十章爬虫笔记陆陆续续记录了一些简单的Python爬虫知识, 用来解决简单的贴吧下载,绩点运算自然不在话下. 不过要想批量下载大量的内容,比如知乎的所有的问答,那便显得游刃不有余了点. 于是乎,爬虫 ...
- 97、爬虫框架scrapy
本篇导航: 介绍与安装 命令行工具 项目结构以及爬虫应用简介 Spiders 其它介绍 爬取亚马逊商品信息 一.介绍与安装 Scrapy一个开源和协作的框架,其最初是为了页面抓取 (更确切来说, ...
随机推荐
- SpringBoot---核心---日志配置
- c++笔记1
using namespace std:命名空间可以保证一些命名能够在全局不冲突.如用户可以通过声明命名空间,然后用运算符::区别同名的不同变量 using namespace std;namespa ...
- 报错:Could not reserve enough space for object heap error
windows命令行运行某个命令时出现: 解决办法: 设置开始->控制面板->系统和安全->系统->高级系统设置->环境变量->系统变量->新建: 变量名: ...
- zeplin 登录效果实现
zeplin 登录效果实现 zeplin 登录页有个效果不错,https://app.zeplin.io/login 可以看看. 主要是输入框的字会随着状态变化而变化. 我这里实现了一个自己的效果 实 ...
- Linux环境 Java内存快速查看
最近生产环境遇到内存老是占用很大的情况,16G的内存Free的内存只剩100多M,仿佛一颗定时炸弹一般,说不定就服务Down了.于是开始网上不断的找查看内存使用的方法.现学现卖,以下通过一个例子来演示 ...
- .NET CORE IIS 500.21
最近遇到的.NET CORE 500.21的错误 官方解决方案地址:https://docs.microsoft.com/en-us/dynamics-nav/troubleshooting-http ...
- 快色排序算法(C语言描述)
快速排序 算法思想 快速排序采用了一种分治策略,学术上称之为分治法(Divide-and-Conquer Method). 哨兵(如下算法中的key) 每趟排序将哨兵插入到数组的合适位置,使得哨兵左侧 ...
- git remote add 用法
前一阵子,对于git remote add 的内容一直调错,现在明确一下: 这里是gitStack的用法:git remote add gitServerName http://ip/name(这里没 ...
- Uncaught exception 'PDOException' with message 'SQLSTATE[HY000] [2002] No such file or directory解决方法
今天用pdo连接mysql遇到一个奇怪的问题,host设为127.0.0.1可以连接成功,设为localhost就会报如下的错误: PHP Fatal error: Uncaught excepti ...
- jmeter的安装和基本使用
本篇文章主要介绍一下JMeter的安装及基本使用方法. 1.安装 JMeter的官方网址为http://jmeter.apache.org/ 下载地址为http://jmeter.apache.org ...