笔记
代码语言:javascript复制-基于Spider的全站数据爬取
-基于网站中某一模板下的全部页码对应的页面数据进行爬取
-需求:爬取校花网中的照片的名称
-实现方式:
-将所有的url添加到start_urls 不推荐使用
-自行手动进行请求的发送
# 手动请求发送 callback回调函数是专门用作与数据解析
yield scrapy.Request(url=new_url,callback=self.parse)
-CrawlSpider的使用
-创建一个工程
-cd xxx
-创建爬虫文件(CrawlSpider):
-Scrapy genspider -t crawl xxx www.xxx.com
-链接提取器
-作用:根据指定的规则(allow)进行指定链接的提取
-规则解析器
-作用:将连接踢球去提取到的链接进行指定规则(callback)的解析
-follow
-follow=True; 可以将连接提取器,继续作用到链接提取器提取到的链接,所对用的页面中
即使有重复的url请求,我们的调度器中的过滤器,也会帮我们给过滤掉
-五大核心组件
Spider:主要进行数据解析
引擎: 所有的流数据都会流经引擎1、用作数据流处理的2、可以触发事务
调度器:
过滤器:将送过来的请求进行去重,去重之后放入队列等待下一步操作
队列:
最终给下载器中
下载器:从互联网上去请求网页资源 异步的操作
管道:进行持久化存储
-请求传参
-使用场景:如果爬取解析的数据不在同一张页面中。(深度爬取)
-需求:爬取boss直聘的岗位名称,岗位描述
图片爬取
需求:爬取站长素材的高清图片的爬取https://sc.chinaz.com/tupian/
笔记
基于scrapy框架爬取字符串类型的数据和爬取图片类型的数据有什么区别
1、字符串,只需要xpath解析且提交管道进行持久化存储
2、图片:xpath解析到图片src属性值。单独对图片地址发起请求获取图片二进制类型的数据数据
ImagesPipeline:
只需要将img的src属性值进行解析,提交到管道,管道就会对图片的src进行请求发送获取到图片的二进制类型的数据,且话可以帮我们进行持久化存储
需求:爬取站长素材的图片爬取https://sc.chinaz.com/tupian/
使用流程:
1、数据解析(图片的地址)
2、将存储图片地址的item提交到指定的管道类
3、管道文件之中自指定一个基于ImagesPipeLine的一个管道类
代码语言:javascript复制def get_media_requests(self, item, info):
#就是可以根据图片地址,进行图片数据的请求
def file_path(self, request, response=None, info=None, *, item=None):
#指定图片储存的路径
def item_completed(self, results, item, info):
return item#返回给下一个即将执行的管道类
4、在配置文件中:
指定图片二点存储目录:IMAGES_STORE=’./imgs_lyz’
指定开启的管道:自定制的管道类
img.py
代码语言:javascript复制import scrapy
from imgsPro.items import ImgsproItem
class ImgSpider(scrapy.Spider):
name = 'img'
allowed_domains = ['www.xxx.com']
start_urls = ['https://sc.chinaz.com/tupian/']
def parse(self, response):
div_list=response.xpath('//*[@id="container"]/div')
for div in div_list:
# 注意:使用伪属性(这具体体现为,图片没在当前页面显示的话,就使用伪属性,显示出来之后才会去使用src属性)
src=div.xpath('./div/a/img/@src2').extract_first()#//*[@id="container"]/div[1]/div/a/img/@src
print(src)
item = ImgsproItem()
item ['src']='https:' src#https://scpic1.chinaz.net/Fileshttps://img.yuanmabao.com/zijie/pic/pic9/202112/apic37626_s.jpg
yield item
pass
pipelines.py
代码语言:javascript复制# Define your item pipelines here
#
# Don't forget to add your pipeline to the ITEM_PIPELINES setting
# See: https://docs.scrapy.org/en/latest/topics/item-pipeline.html
# useful for handling different item types with a single interface
import scrapy
from itemadapter import ItemAdapter
# class ImgsproPipeline:
# def process_item(self, item, spider):
# return item
from scrapy.pipelines.images import ImagesPipeline
class imgsPipeline(ImagesPipeline):
#重写父类中的三个方法
def get_media_requests(self, item, info):
#就是可以根据图片地址,进行图片数据的请求
yield scrapy.Request(item['src'])
def file_path(self, request, response=None, info=None, *, item=None):
#指定图片储存的路径
img_name=request.url.split('/')[-1]
return img_name
pass
def item_completed(self, results, item, info):
return item#返回给下一个即将执行的管道类
pass
pass
items.py
代码语言:javascript复制# Define here the models for your scraped items
#
# See documentation in:
# https://docs.scrapy.org/en/latest/topics/items.html
import scrapy
class ImgsproItem(scrapy.Item):
# define the fields for your item here like:
#
src = scrapy.Field()
pass
setting.py
代码语言:javascript复制USER_AGENT = 'ua检测'
ROBOTSTXT_OBEY = False
LOG_LEVEL='ERROR'
#去除注释,更改成自己写的管道类名
ITEM_PIPELINES = {
'imgsPro.pipelines.imgsPipeline': 300,
}
#指定图片存储的目录
IMAGES_STORE='./imgs_lyz'
中间件
引擎和下载中间的是下载中间件 |||||重点
引擎和spider中间的是爬虫中间件
下载中间件:
作用:批量拦截到到整个工程中所有的请求和响应
拦截请求:
1、UA伪装 process_request 2、代理IP的设定 process_exception return request
拦截响应:
1、篡改响应数据,相应对象
拦截请求
爬取百度模拟拦截之后使用ua伪装和ip代理进行爬取
middlewares.py
代码语言:javascript复制class MiddleproDownloaderMiddleware:
user_agent_list = [
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.1 "
"(KHTML, like Gecko) Chrome/22.0.1207.1 Safari/537.1",
"Mozilla/5.0 (X11; CrOS i686 2268.111.0) AppleWebKit/536.11 "
"(KHTML, like Gecko) Chrome/20.0.1132.57 Safari/536.11",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.6 "
"(KHTML, like Gecko) Chrome/20.0.1092.0 Safari/536.6",
"Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.6 "
"(KHTML, like Gecko) Chrome/20.0.1090.0 Safari/536.6",
"Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.1 "
"(KHTML, like Gecko) Chrome/19.77.34.5 Safari/537.1",
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/536.5 "
"(KHTML, like Gecko) Chrome/19.0.1084.9 Safari/536.5",
"Mozilla/5.0 (Windows NT 6.0) AppleWebKit/536.5 "
"(KHTML, like Gecko) Chrome/19.0.1084.36 Safari/536.5",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.3 "
"(KHTML, like Gecko) Chrome/19.0.1063.0 Safari/536.3",
"Mozilla/5.0 (Windows NT 5.1) AppleWebKit/536.3 "
"(KHTML, like Gecko) Chrome/19.0.1063.0 Safari/536.3",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_0) AppleWebKit/536.3 "
"(KHTML, like Gecko) Chrome/19.0.1063.0 Safari/536.3",
"Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.3 "
"(KHTML, like Gecko) Chrome/19.0.1062.0 Safari/536.3",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.3 "
"(KHTML, like Gecko) Chrome/19.0.1062.0 Safari/536.3",
"Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.3 "
"(KHTML, like Gecko) Chrome/19.0.1061.1 Safari/536.3",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.3 "
"(KHTML, like Gecko) Chrome/19.0.1061.1 Safari/536.3",
"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/536.3 "
"(KHTML, like Gecko) Chrome/19.0.1061.1 Safari/536.3",
"Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.3 "
"(KHTML, like Gecko) Chrome/19.0.1061.0 Safari/536.3",
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.24 "
"(KHTML, like Gecko) Chrome/19.0.1055.1 Safari/535.24",
"Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/535.24 "
"(KHTML, like Gecko) Chrome/19.0.1055.1 Safari/535.24"
]
PROXY_http = [
'153.180.102.104:80',
'195.208.131.189:56055',
]
PROXY_https = [
'120.83.49.90:9000',
'95.189.112.214:35508',
]
def process_request(self, request, spider):
#拦截请求的
#ua伪装
request.headers['User-Agent']=random.choice(self.user_agent_list)
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):
#拦截发生异常的请求
#代理IP,请求被拦截之后,换一个ip进行爬取
if request.url.split(':')[0]=='http':
request.meta['proxy']='http://' random.choice(self.PROXY_http)
else:
request.meta['proxy']='https://' random.choice(self.PROXY_https)
return request#将修正之后的请求对象进行重新的请求发送
settings.py
代码语言:javascript复制ROBOTSTXT_OBEY = False
DOWNLOADER_MIDDLEWARES = {
'middlePro.middlewares.MiddleproDownloaderMiddleware': 543,
}
middle.py
代码语言:javascript复制import scrapy
class MiddleSpider(scrapy.Spider):
#请求的拦截,爬取百度
name = 'middle'
#allowed_domains = ['www.xxx.com']
start_urls = ['https://www.baidu.com/s?wd=ip']
def parse(self, response):
page_txt=response.text
with open ('ip.html','w',encoding='utf-8')as fp:
fp.write(page_txt)
pass
拦截响应
需求爬取网易新闻中的新闻数据(标题和内容)
1、通过网易新闻的首页解析出来五大板块对应的详情页url(没有动态加载)
2、每一个板块对应的新闻标题都是动态加载出来的(动态加载)
3、通过解析出每一个新闻详情页的url获取详情页的页面源码,解析出来新闻内容
需求:爬取网易新闻基于Scrapy爬取网易新闻中的新闻数据
wangyi.py
代码语言:javascript复制import scrapy
from selenium import webdriver
from wangyiPro.items import WangyiproItem
class WangyiSpider(scrapy.Spider):
name = 'wangyi'
allowed_domains = ['www.xxx.com']
start_urls = ['https://news.163.com/']
model_url_list=[]#存储五大板块对应详情页的url
#解析五大板块对应详情页的url
def parse(self, response):
li_list=response.xpath('//*[@id="index2016_wrap"]/div[1]/div[2]/div[2]/div[2]/div[2]/div/ul/li')
alist=[2,3,5,6,8]
for index in alist:
li=li_list[index]
model_url=li.xpath('.//a/@href').extract_first()
print(model_url)
self.model_url_list.append(model_url)
#依次对每一个板块对应的页面进行请求
for url in self.model_url_list:
yield scrapy.Request(url,callback=self.parse_model)
print('第一步完成')
#每一个板块的对应的新闻标题相关内容都是动态加载出来的
def parse_model(self,response):
#解析灭一个板块页面中对应的新闻的标题和新闻详情页的url
print('第二步')
div_list=response.xpath('/html/body/div/div[3]/div[4]/div[1]/div[1]/div/ul/li/div/div')
for div in div_list:
title=div.xpath('/div/div[1]/h3/a/text()').extract_first()
new_detail_url=div.xpath('./a/@href').extract_first()
item=WangyiproItem()
item['title']=title
yield scrapy.Request(url= new_detail_url, callback=self.parse_detail,meta={'item':item})
pass
def parse_detail(self,response):
print('第三步')
content=response.xpath('//*[@id="content"]/div[2]//text()').extract()
content='' content
item=response.meta['item']
item['content']=content
yield item
pass
# 实例化一个浏览器对象
def __init__(self):
self.bro=webdriver.Chrome(executable_path='chromedriver.exe')
pass
items.py
代码语言:javascript复制import scrapy
class WangyiproItem(scrapy.Item):
# define the fields for your item here like:
title=scrapy.Field()
content= scrapy.Field()
pass
middlewares.py
代码语言:javascript复制from itemadapter import is_item, ItemAdapter
from scrapy.http import HtmlResponse
from time import sleep
class WangyiproDownloaderMiddleware:
def process_response(self, request, response, spider):
#通过该方法拦截五大板块对应的响应对象,进行篡改
#挑选出指定的响应对象进行篡改
#spider是爬虫的对象
bro=spider.bro#获取了爬虫类中定义的浏览器对象
if request.url in spider.model_url_list:
# response#五大板块对应的响应对象
#针对定位到这些的response进行篡改
#实例化一个新的响应对象(符合需求:包含动态加载出来的新闻数据),代替原来旧的响应对象
#如何获取动态加载的数据
# 基于selenium便捷的获取动态加载的数据
bro.get(request.url) # 五大板块对应的url进行请求发送
sleep(5)
page_text = bro.page_source # 包含了动态记载的新闻数据
new_response=HtmlResponse(url=request.url,body=page_text,encoding='utf-8',request=request)
return new_response
else:
#response#其他请求对应的响应对象
return response
def process_exception(self, request, exception, spider):
pass
pipelines.py
代码语言:javascript复制class WangyiproPipeline:
# 专门用来处理item类型对象
# 该方法可以接受爬虫文件提交过来的item对象
# 该方法没接收到一个item就会被调用一次
def process_item(self, item, spider):
print(item)
return item
CrawlSpider
他就是一个基于spider的一个子类CrawlSpider;专门去做的全站数据的爬取
全站数据爬取的方式
基于spider:手动请求发送(利用页面通用的url进行页面的请求的发送)
基于CrawlSpider:
CrawlSpider的具体使用
1、创建一个工程
2、cd XXX
3、创建爬虫文件(CrawlSpider):
代码语言:javascript复制# 创建爬虫文件
scrapy genspider -t crawl xxx www.xxx.com
链接提取器:根据指定规则(allow=r’Items/ r’Items/‘是一个正则表达式)进行指定连接的提取,根据指定规则allow,进行连接爬取
规则解析器:将链接解析器提取到的链接进行制定规则(callback)的解析操作
找不到url链接提取去没有用没有再看
demo
代码语言:javascript复制import scrapy
from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Rule
from lxml import etree
#这个就是全站爬取的demo
#5.18这个针对于个人信息,可以利用他的搜索进行查找到每一个人对应的数据,这个将大大降低我们搜索的时间和难度;针对于他的题库类型要使用全站爬取的这种方式进行爬取
class DemoproSpider(CrawlSpider):
name = 'demoPro'
#allowed_domains = ['www.xxx.com']
start_urls = ['http://acm.zzuli.edu.cn/ranklist.php']
# 实例化了一个规则解析器;
# 三个参数所表示的意思
# LinkExtractor链接提取器:根据指定规则(allow="正则表达式"),进行指定连接的提取
link=LinkExtractor(allow=r'start=d ')
rules = (
#规则解析器 将链接提取器提取到的链接进行制定规则(callback)的解析操作
#链接提取器提取到的链接,callback就会执行几次
Rule(link, callback='parse_item', follow=True),
#follow=True; 可以将连接提取器,继续作用到链接提取器提取到的链接,所对用的页面中
#即使有重复的url请求,我们的调度器中的过滤器,也会帮我们给过滤掉
)
def parse_item(self, response):#大概就是做数据分析的
item = {}
#item['domain_id'] = response.xpath('//input[@id="sid"]/@value').get()
#item['name'] = response.xpath('//div[@id="name"]').get()
#item['description'] = response.xpath('//div[@id="description"]').get()
print(response)
item = {}
page_txt = response.text
# /html/body/div[1]/div/table/tbody
tree = etree.HTML(page_txt)
tr_list = tree.xpath('/html/body/div[1]/div/table/tbody/tr')
for item in tr_list:
userid = item.xpath('./td[2] / div / a/text()')[0]
username = item.xpath('./td[3]/div/text()')[0]
adad = item.xpath('./td[4]/div/a/text()')[0]
qweqwe = item.xpath("./td[5]/div/a/text()")[0]
bilv = item.xpath("./td[6]/div/text()")[0]
jibie = item.xpath("./td[7]/div/text()")[0]
#if userid == "201908064618":
print(userid "||" username "|" adad "||" qweqwe "||" bilv "||" jibie)
print(tr_list.__len__())
return item
问题
小插曲
时间长没有做python了,又重装了系统,这爬虫这部分就一直在搁置,这打开程序发现终端识别不到scrapy程序命令。但是在pycharm确实是下载的又这个库
解决
就是在终端删除这个库,我的是他就提示这个库它本身就没有下载,然后我就先下载了一下