CrawlSpider全站爬取某君cos妹子图
本帖最后由 wananzuiqingfen 于 2020-11-22 22:38 编辑介绍加入鱼C大家庭已经半年了,没啥好表示的,既然大家都和我一样喜欢妹子{:10_281:} ,那我也得表示表示了。
目标:全站爬取cos君本子板块妹子图
{:10_281:} : https://www.cosjun.cn/benzi桜桃喵 蕾姆紫睡裙 镇楼:
全套服务{:10_281:} :
教程
1、提取所有页面链接
首先,使用如下两行基于终端的命令创建一个基于 CrawlSpider 的爬虫项目:
scrapy startproject CosJunPro
scrapy genspider -t crawl cos xxoo.com接着,我们来到目标链接{:10_281:}{:10_281:}{:10_281:}: https://www.cosjun.cn/benzi
F12 打开开发者工具,页面拖动到最底部,选择任意分页按钮,观察其结构,可以发现,每一页的链接包含在 li 标签中,而 li 标签又被包含在一个 ul 标签中,并且它的 class 属性为 "page-numbers":
首先,我们需要提取这些主页面的链接,我们使用 Xpath 来解析源码,修改默认生成的爬虫文件如下:
# cos.py
import scrapy
from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Rule
class CosSpider(CrawlSpider):
name = 'cos'
# 我们不禁止爬取的域名
# allowed_domains = ['xxoo.com']
start_urls = ['https://www.cosjun.cn/benzi']
rules = (
# 提取所有主页面的链接并访问
Rule(LinkExtractor(restrict_xpaths='//ul[@class="page-numbers"]'), callback='parse_item', follow=True),
)
def parse_item(self, response):
# 作为演示,我们检查响应状态
print(response)
我们定义了一个关于主页面链接提取并自动请求的 Rule 对象,设置了回调,以及 follow 设置为 True,我们希望链接提取器继续作用于这些被提取到的页面。
在回调函数 parse_item 中,为了演示结果,我们打印响应对象。
2、提取所有详情页链接
接着,我们需要提取所用妹子专辑详情页的链接{:10_281:}
通过开发者工具,任意选中一部专辑,观察其网页结构,可以发现,每张专辑都包含在一个 div 标签中,而这些 div 标签又包含在一个 div 标签中,且它的 class 属性为 "row" 和 "posts-wrapper":
这里虽然涉及到属性多值匹配,但楼主测试的时候使用 contains 不起作用,反倒是直接整个拷贝过去能行{:10_264:} 。
我们更新 rolus,添加一个关于详情页的 Rule :
rules = (
# 提取所有主页面的链接并访问
Rule(LinkExtractor(restrict_xpaths='//ul[@class="page-numbers"]'), callback='parse_item', follow=True),
# 提取详情页的链接并访问
Rule(LinkExtractor(restrict_xpaths='//div[@class="row posts-wrapper"]'), callback='parse_detaill',follow=False),
)
对详情页的请求得到响应后,我们希望调用 parse_detail 回调函数来处理,我们将会在后面编写这个函数, follow 设置为 False 是因为链接提取器没有必要再作用于详情页中了。
3、解析详情页我们点击任意专辑,进入妹子写真详情页{:10_281:}。
友情提示: 提供给游客的图片只有6张,但是登陆之后会提供全部图片,此外,针对普通用户,只开放部分免费写真全集,大部分有 vip 权限的专辑对普通用户同样只开放6张图片,不过已经够用了{:10_254:}
打开开发者工具,检索图片的链接地址,其网页结构如下所示,每张图片的链接包含在一个 figure 标签中,这些标签又包含在一个 div 标签中,且它有一个唯一的 id 属性值 "gallery-1"
注意,在登录状态下,如果某个专辑是免费的,那么登录后解锁的第二部分将会加载,它的数据结构和上述类似,唯一不同的是div 标签的唯一的 id 属性值变成了 "gallery-2":
由于免费专辑的数量感人,因此是否实现携带 Cookies任君抉择,我将 Cookies 的设置以及免费生成 Cos 君账号的问题作为了一个单独的小节,如有需要,请点击上方目录跳转查看。
由上述示例图片,我们已经知道了提取图片链接的思路: 首先定位figure 标签,在定位 div标签,接着定位 a标签提取到图片的链接地址。
此外,我们应该提取专辑的名称作为某一部专辑存储的目录名称,此外,我们还可以提取妹子的名称作为存储关于该妹子的目录名{:10_281:}。
专辑标题的网页结构如下,额外的,我们可以在提取到标题后,继续提取出妹子的名字{:10_281:}:
提取标题的思路为:利用 class 属性值 "entry-header" 定位到 header 标签,在定位到下面的 h1 标签,提取出文本数据即可。
上述的全部工作将由 parse_detail 完成,在编写 parse_detail 之前,我们在 items.py 文件中需要为图片链接和图片标题、妹子名称创建 Item 字段:
# items.py
import scrapy
class CosproItem(scrapy.Item):
# 图片链接、专辑标题、妹子名称
img_src = scrapy.Field()
img_title = scrapy.Field()
sister_name = scrapy.Field()
接着,我们将写好的 CosproItem 导入到 cos.py 文件中,编写我们的 parse_detail:
import scrapy
from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Rule
from CosJunPro.items import CosproItem
class CosSpider(CrawlSpider):
name = 'cos'
# 我们不禁止爬取的域名
# allowed_domains = ['xxoo.com']
start_urls = ['https://www.cosjun.cn/benzi']
rules = (
# 提取所有主页面的链接并访问
Rule(LinkExtractor(restrict_xpaths='//ul[@class="page-numbers"]'), callback='parse_item', follow=False),
# 提取详情页的链接并访问
Rule(LinkExtractor(restrict_xpaths='//div[@class="row posts-wrapper"]'), callback='parse_detail',follow=False),
)
def parse_item(self, response):
# 作为演示,我们检查响应状态
print(response)
def parse_detail(self,response):
print(response)
# 所有图片的figure标签的序列,用可能存在的第二部分扩展这个序列
figure_list = response.xpath('//div[@id="gallery-1"]/figure')
list2 = response.xpath('//div[@id="gallery-2"]/figure')
figure_list.extend(list2)
# 本子的标题和妹子的名称
img_title = response.xpath('//header[@class="entry-header"]//h1/text()').extract_first()
sister_name = img_title.split(' ')
for figure in figure_list:
# 详情页每张图片的url
img_src = figure.xpath('./div/a/@href').extract_first()
# 将数据封装到容器中
item = CosproItem()
item['img_title'] = img_title
item['img_src'] = img_src
item['sister_name'] = sister_name
yield item
4、管道
Scrapy 提供非常方便的用于文件下载或图片下载的 ImagesPipeline 管道类,我们将基于这个管道类来下载图片:
import scrapy
from scrapy.exceptions import DropItem
from scrapy.pipelines.images import ImagesPipeline
class CosjunproPipeline(ImagesPipeline):
def get_media_requests(self, item, info):
# 手动发起请求
yield scrapy.Request(item['img_src'], meta={'item': item})
def file_path(self, request, response=None, info=None, *, item=None):
item = request.meta['item']
# 文件路径
ImgName = f'/{item["sister_name"]}/{item["img_title"]}/' + request.url.split('/')[-1]
return ImgName
def item_completed(self, results, item, info):
img_urls = for ok, x in results if ok]
if not img_urls:
raise DropItem('Item download failure')
else:
for url in img_urls:
print(item['img_title'], '下载成功: ', url)
return item
我们在 get_media_requests 方法中手动发起请求,并传递 Item 对象,
这么做是为了在 file_path 方法中,构建文件名时,我们使用妹子名作为一级目录,关于这个妹子的某一部写着作为二级目录,所有的图片存储在对应的写真目录中。
在 item_completed 方法中,我们检测请求的结果,results 是一个列表,请求的结果作为一个元组存储在其中,如下所示:
[(True, {
'url': 'https://www.cosjun.cn/wp-content/uploads/2020/11/1605443477-f55cf0d2d7e653c.jpg',
'path': './test.jpg',
'checksum': '89758c526d5db6541f2c9466691f5c61',
'status': 'uptodate'}),
元组的第一个元素对应请求的结果,第二个元素是一个字典,其中存储了某些信息,我们通过一个列表推导式提取出字典的 url 键值。
如果这个列表是空的,意味着我们下载失败了,那么就抛出 DropItem 异常,停止处理这个 Item。反之,我们打印消息表示成功下载。
接着,我们需要在配置文件开启管道,以及定义基于 ImagePipeline 管道的存储路径:
# settings.py
ITEM_PIPELINES = {
'CosJunPro.pipelines.CosjunproPipeline': 300,
}
IMAGES_STORE = '../COS_Test'
5、中间件
为了避免 ip 被封禁而导致爬取失败,我们将在下载中间件中设置随机 UA、使用代理、处理异常的请求:
# middlewares.py
from fake_useragent import UserAgent
from Xiaoming.zhima_proxy import get_proxy_pool
class CosjunproDownloaderMiddleware:
# 用于设置随机UA标识
ua = UserAgent()
PROXY_https = get_proxy_pool('https', 20) # https 协议代理ip
def process_request(self, request, spider):
request.headers['User-Agent'] = self.ua.random
# 为初次请求使用代理
if request.url == spider.start_urls:
request.meta['proxy'] = 'https://' + self.PROXY_https.pop()
return None
def process_exception(self, request, exception, spider):
# 为异常的请求更换ip
request.meta['proxy'] = 'https://' + self.PROXY_https.pop()
return request
有关于 get_proxy_pool 函数详见白嫖高匿 ip 小节,这里不多做赘述,其具体作用就是接受协议头以及请求的代理 ip 个数这两个参数,来返回一个对应的代理 ip 列表。
关于 fake_useragent 模块UserAgent 类,它是一个用于生成随机UA的很好的实现,每次调用其实例化对象的 random 就可以得到一个随机的 UA 标识。
接着我们需要在 settings.py 文件中开启下载中间件,以及设置一些其他的配置:
DOWNLOADER_MIDDLEWARES = {
'CosJunPro.middlewares.CosjunproDownloaderMiddleware': 543,
}
# 是否遵从robots.txt协议
ROBOTSTXT_OBEY = False
# 设置日志等级,使输出更为简洁
LOG_LEVEL = 'ERROR'
最后,运行我们的爬虫程序即可:scrapy crawl cos
输出结果如下:
文件目录如我们预期的一样被创建,以妹子名作为一级目录,有关于该妹子的写真作为二级目录,其中存储了这一部写真的图片:
第一次发帖没经验,思来想去不知道要不要做成教程贴,感觉这些东西都是很基本的,我要是唧唧歪歪列一堆大家都知道的东西显得有点没意义,索引就当成爬妹子图乐呵乐呵。
如果您是新手,有关于上述代码不懂的地方可以@我,能力范围内,我会尽量解答您的问题{:10_264:}
{:10_281:}{:10_281:}{:10_281:} 喜欢的话给我点个赞吧~
源码
1、爬虫文件 cos.py
import scrapy
from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Rule
from CosJunPro.items import CosproItem
class CosSpider(CrawlSpider):
name = 'cos'
# 我们不禁止爬取的域名
# allowed_domains = ['xxoo.com']
start_urls = ['https://www.cosjun.cn/benzi']
rules = (
# 提取所有主页面的链接并访问
Rule(LinkExtractor(restrict_xpaths='//ul[@class="page-numbers"]'), callback='parse_item', follow=False),
# 提取详情页的链接并访问
Rule(LinkExtractor(restrict_xpaths='//div[@class="row posts-wrapper"]'), callback='parse_detail',follow=False),
)
def parse_item(self, response):
# 作为演示,我们检查响应状态
print(response)
def parse_detail(self,response):
print(response)
# 所有图片的figure标签的序列,用可能存在的第二部分扩展这个序列
figure_list = response.xpath('//div[@id="gallery-1"]/figure')
list2 = response.xpath('//div[@id="gallery-2"]/figure')
figure_list.extend(list2)
# 本子的标题和妹子的名称
img_title = response.xpath('//header[@class="entry-header"]//h1/text()').extract_first()
sister_name = img_title.split(' ')
for figure in figure_list:
# 详情页每张图片的url
img_src = figure.xpath('./div/a/@href').extract_first()
# 将数据封装到容器中
item = CosproItem()
item['img_title'] = img_title
item['img_src'] = img_src
item['sister_name'] = sister_name
yield item
2、items.py
import scrapy
class CosproItem(scrapy.Item):
# 图片链接、专辑标题、妹子名称
img_src = scrapy.Field()
img_title = scrapy.Field()
sister_name = scrapy.Field()
3、middlewares.py
from fake_useragent import UserAgent
from Xiaoming.zhima_proxy import get_proxy_pool
class CosjunproDownloaderMiddleware:
# 用于设置随机UA标识
ua = UserAgent()
PROXY_https = get_proxy_pool('https', 20) # https 协议代理ip
def process_request(self, request, spider):
request.headers['User-Agent'] = self.ua.random
# 为初次请求使用代理
if request.url == spider.start_urls:
request.meta['proxy'] = 'https://' + self.PROXY_https.pop()
return None
def process_exception(self, request, exception, spider):
# 为异常的请求更换ip
request.meta['proxy'] = 'https://' + self.PROXY_https.pop()
return request
4、pipeline.py
import scrapy
from scrapy.exceptions import DropItem
from scrapy.pipelines.images import ImagesPipeline
class CosjunproPipeline(ImagesPipeline):
def get_media_requests(self, item, info):
# 手动发起请求
yield scrapy.Request(item['img_src'], meta={'item': item})
def file_path(self, request, response=None, info=None, *, item=None):
item = request.meta['item']
# 文件路径
ImgName = f'/{item["sister_name"]}/{item["img_title"]}/' + request.url.split('/')[-1]
return ImgName
def item_completed(self, results, item, info):
img_urls = for ok, x in results if ok]
if not img_urls:
raise DropItem('Item download failure')
else:
for url in img_urls:
print(item['img_title'], '下载成功: ', url)
return item
5、settings.py
# Scrapy settings for CosJunPro project
#
# For simplicity, this file contains only settings considered important or
# commonly used. You can find more settings consulting the documentation:
#
# https://docs.scrapy.org/en/latest/topics/settings.html
# https://docs.scrapy.org/en/latest/topics/downloader-middleware.html
# https://docs.scrapy.org/en/latest/topics/spider-middleware.html
BOT_NAME = 'CosJunPro'
SPIDER_MODULES = ['CosJunPro.spiders']
NEWSPIDER_MODULE = 'CosJunPro.spiders'
# Crawl responsibly by identifying yourself (and your website) on the user-agent
#USER_AGENT = 'CosJunPro (+http://www.yourdomain.com)'
# Obey robots.txt rules
#ROBOTSTXT_OBEY = True
# 是否遵从robots.txt协议
ROBOTSTXT_OBEY = False
# 日志信息
LOG_LEVEL = 'ERROR'
# Configure maximum concurrent requests performed by Scrapy (default: 16)
#CONCURRENT_REQUESTS = 32
# Configure a delay for requests for the same website (default: 0)
# See https://docs.scrapy.org/en/latest/topics/settings.html#download-delay
# See also autothrottle settings and docs
#DOWNLOAD_DELAY = 3
# The download delay setting will honor only one of:
#CONCURRENT_REQUESTS_PER_DOMAIN = 16
#CONCURRENT_REQUESTS_PER_IP = 16
# Disable cookies (enabled by default)
#COOKIES_ENABLED = False
# Disable Telnet Console (enabled by default)
#TELNETCONSOLE_ENABLED = False
# Override the default request headers:
#DEFAULT_REQUEST_HEADERS = {
# 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
# 'Accept-Language': 'en',
#}
# Enable or disable spider middlewares
# See https://docs.scrapy.org/en/latest/topics/spider-middleware.html
#SPIDER_MIDDLEWARES = {
# 'CosJunPro.middlewares.CosjunproSpiderMiddleware': 543,
#}
# Enable or disable downloader middlewares
# See https://docs.scrapy.org/en/latest/topics/downloader-middleware.html
DOWNLOADER_MIDDLEWARES = {
'CosJunPro.middlewares.CosjunproDownloaderMiddleware': 543,
}
# Enable or disable extensions
# See https://docs.scrapy.org/en/latest/topics/extensions.html
#EXTENSIONS = {
# 'scrapy.extensions.telnet.TelnetConsole': None,
#}
# Configure item pipelines
# See https://docs.scrapy.org/en/latest/topics/item-pipeline.html
ITEM_PIPELINES = {
'CosJunPro.pipelines.CosjunproPipeline': 300,
}
IMAGES_STORE = '../COS_Test'
# Enable and configure the AutoThrottle extension (disabled by default)
# See https://docs.scrapy.org/en/latest/topics/autothrottle.html
#AUTOTHROTTLE_ENABLED = True
# The initial download delay
#AUTOTHROTTLE_START_DELAY = 5
# The maximum download delay to be set in case of high latencies
#AUTOTHROTTLE_MAX_DELAY = 60
# The average number of requests Scrapy should be sending in parallel to
# each remote server
#AUTOTHROTTLE_TARGET_CONCURRENCY = 1.0
# Enable showing throttling stats for every response received:
#AUTOTHROTTLE_DEBUG = False
# Enable and configure HTTP caching (disabled by default)
# See https://docs.scrapy.org/en/latest/topics/downloader-middleware.html#httpcache-middleware-settings
#HTTPCACHE_ENABLED = True
#HTTPCACHE_EXPIRATION_SECS = 0
#HTTPCACHE_DIR = 'httpcache'
#HTTPCACHE_IGNORE_HTTP_CODES = []
#HTTPCACHE_STORAGE = 'scrapy.extensions.httpcache.FilesystemCacheStorage'
白嫖高匿ip
爬虫的世界怎么能少的了代理 ip 呢?
不装了,我摊牌了,我是芝麻代理50年铁粉,当他们的公司还没有创建时,我冥冥之中就感觉他们一定能有大作为,唉,这该死的缘分呀~
为什么那么多代理 ip 服务商,我只推荐芝麻? 嘿嘿,那当然是因为它家可以白嫖呀{:10_254:} 。
首先,我们来到官网注册一个账号: http://h.zhimaruanjian.com/
接着在导航栏点击获取API,跳转到代理 ip 的 API 链接生成页面,每天可以领取20个免费的高匿 ip:
注意: 新注册的账号需要找客服帮你解开限制。
接下来,我们生成一个代理 ip 的 API 链接,在这里,我们没有更改任何的配置选项,
根据你的实际需求勾选的(它和 API 链接的参数是对应的,更改 API 参数也可以做到修改配置,官网有详细的参数对应的配置表,可以自行查看):
点击生成 API 链接,从直连IP、独享IP、隧道IP随意选择一个 API 链接复制即可。
我们用 Python 来请求这个 API 链接:
import requests
api_url = '复制的api链接'
res = requests.get(api_url)
res.text
我们得到的响应结果为: '123.97.109.156:4257\r\n'
如何测试这个 ip 的质量呢?官方提供了一个 ip 检测工具,我们用这个测试即可: http://h.zhimaruanjian.com/agent/
我们提取到的这个 ip 的检测结果为:
除了白嫖,芝麻还提供按次购买的服务,对于刚入门需求量较小的用户是一个不错的选择。
最后,我需要发誓我不是芝麻的托,不然我的弟弟一辈子抬不起头{:10_327:}
解决账号问题
如果你要丧心病狂的使用 Cookies 池进行爬取,那么困扰你的一定是账号的问题,因为 Cos 君是基于邮箱注册账号的。
所以,我们只需要在网上找一个提供邮箱代收的站点即可,随用随取: https://www.linshiyouxiang.net/
我只对高匿ip感兴趣{:10_285:} 笨鸟学飞 发表于 2020-11-22 19:08
我只对高匿ip感兴趣
卧槽,我都没编辑完就有人了? 我现在还在解决图片排版问题,高匿ip去芝麻代理就可以了,每天免费20个
芝麻: http://h.zhimaruanjian.com/pay/
笨鸟学飞 发表于 2020-11-22 19:08
我只对高匿ip感兴趣
代理 ip 弄好了,你可以看看{:10_264:} 纯学习{:5_91:}
页:
[1]