前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >爬虫相关

爬虫相关

作者头像
IT茂茂
发布2020-03-05 19:58:10
1.1K0
发布2020-03-05 19:58:10
举报
文章被收录于专栏:IT 茂茂IT 茂茂IT 茂茂

爬虫常用库

requests、selenium、puppeteer,beautifulsoup4、pyquery、pymysql、pymongo、redis、lxml和scrapy框架

其中发起请求课可以使用requests和scrapy

解析内容可以用 beautifulsoup4,lxml,pyquery

存储内容可以使用 mysql(清洗后的数据) redis(代理池) mongodb(未清洗的数据)

抓取动态渲染的内容可以使用:selenium,puppeteer

增量爬虫

一个网站,本来一共有10页,过段时间之后变成了100页。假设,已经爬取了前10页,为了增量爬取,我们现在只想爬取第11-100页。

因此,为了增量爬取,我们需要将前10页请求的指纹保存下来。以下命令是将内存中的set里指纹保存到本地硬盘的一种方式。

scrapy crawl somespider -s JOBDIR=crawls/somespider-1 但还有更常用的,是将scrapy中的指纹存在一个redis数据库中,这个操作已经有造好轮子了,即scrapy-redis库。

scrapy-redis库将指纹保存在了redis数据库中,是可以持久保存的。(基于此,还可以实现分布式爬虫,那是另外一个用途了)scrapy-redis库不仅存储了已请求的指纹,还存储了带爬取的请求,这样无论这个爬虫如何重启,每次scrapy从redis中读取要爬取的队列,将爬取后的指纹存在redis中。如果要爬取的页面的指纹在redis中就忽略,不在就爬取。

Scrapy 相关

crapy基于twisted异步IO框架,downloader是多线程的。

但是,由于python使用GIL(全局解释器锁,保证同时只有一个线程在使用解释器),这极大限制了并行性,在处理运算密集型程序的时候,Python的多线程效果很差,而如果开多个线程进行耗时的IO操作时,Python的多线程才能发挥出更大的作用。(因为Python在进行长时IO操作时会释放GIL) 所以简单的说,scrapy是多线程的,不需要再设置了,由于目前版本python的特性,多线程地不是很完全,但实际测试scrapy效率还可以。

requests 是一个基本库,目前只能用来发送http请求,所以涉及爬虫的多线程或者协程需要自己定制编写

Scrapy整体架构

• 引擎(Scrapy Engine),用来处理整个系统的数据流处理,触发事务 。

• 调度器(Scheduler),用来接受引擎发过来的请求,压入队列中,并在引擎再次请求的时候返回。

• 下载器(Downloader),用于下载网页内容,并将网页内容返回给蜘蛛。

• 蜘蛛(Spiders),蜘蛛是主要干活的,用它来制订特定域名或网页的解析规则。编写用于分析response并提取item(即获取到的item)或额外跟进的URL的类。每个spider负责处理一个特定(或一些)网站。

• 项目管道(ItemPipeline),负责处理有蜘蛛从网页中抽取的项目,他的主要任务是清晰、验证和存储数据。当页面被蜘蛛解析后,将被发送到项目管道,并经过几个特定的次序处理数据。

• 下载器中间件(DownloaderMiddlewares),位于Scrapy引擎和下载器之间的钩子框架,主要是处理Scrapy引擎与下载器之间的请求及响应。

• 蜘蛛中间件(SpiderMiddlewares),介于Scrapy引擎和蜘蛛之间的钩子框架,主要工作是处理蜘蛛的响应输入和请求输出。

• 调度中间件(SchedulerMiddlewares),介于Scrapy引擎和调度之间的中间件,从Scrapy引擎发送到调度的请求和响应。

爬取流程:上图绿线是数据流向,

首先从初始URL开始,Scheduler会将其交给Downloader进行下载,下载之后会交给Spider进行分析,

Spider分析出来的结果有两种:

一种是需要进一步抓取的链接,例如之前分析的“下一页”的链接,这些东西会被传回Scheduler;

另一种是需要保存的数据,它们则被送到Item Pipeline那里,那是对数据进行后期处理(详细分析、过滤、存储等)的地方。

另外,在数据流动的通道里还可以安装各种中间件,进行必要的处理。

数据流(流程,类似抓取任务生命周期)

Scrapy中的数据流由执行引擎控制,其过程如下:

1.引擎打开一个网站(open adomain),找到处理该网站的Spider并向该spider请求第一个要爬取的URL(s)。

2.引擎从Spider中获取到第一个要爬取的URL并在调度器(Scheduler)以Request调度。

3.引擎向调度器请求下一个要爬取的URL。

4.调度器返回下一个要爬取的URL给引擎,引擎将URL通过下载中间件(请求(request)方向)转发给下载器(Downloader)。

5.一旦页面下载完毕,下载器生成一个该页面的Response,并将其通过下载中间件(返回(response)方向)发送给引擎。

6.引擎从下载器中接收到Response并通过Spider中间件(输入方向)发送给Spider处理。

7.Spider处理Response并返回爬取到的Item及(跟进的)新的Request给引擎。

8.引擎将(Spider返回的)爬取到的Item给ItemPipeline,将(Spider返回的)Request给调度器。

9.(从第二步)重复直到调度器中没有更多地request,引擎关闭该网站。

安装

pip install Scrapy

缺少twisted装不上的直接去网上下载动态库:https://www.lfd.uci.edu/~gohlke/pythonlibs/#twisted

新建项目

scrapy startproject 'project_name'
scrapy 配置文件

#==>第一部分:基本配置<===
#1、项目名称,默认的USER_AGENT由它来构成,也作为日志记录的日志名
BOT_NAME = 'Amazon'

#2、爬虫应用路径
SPIDER_MODULES = ['Amazon.spiders']
NEWSPIDER_MODULE = 'Amazon.spiders'

#3、客户端User-Agent请求头
#USER_AGENT = 'Amazon (+http://www.yourdomain.com)'

#4、是否遵循爬虫协议
# Obey robots.txt rules
ROBOTSTXT_OBEY = False

#5、是否支持cookie,cookiejar进行操作cookie,默认开启
#COOKIES_ENABLED = False

#6、Telnet用于查看当前爬虫的信息,操作爬虫等...使用telnet ip port ,然后通过命令操作
#TELNETCONSOLE_ENABLED = False
#TELNETCONSOLE_HOST = '127.0.0.1'
#TELNETCONSOLE_PORT = [6023,]

#7、Scrapy发送HTTP请求默认使用的请求头
#DEFAULT_REQUEST_HEADERS = {
# 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
# 'Accept-Language': 'en',
#}

 

#===>第二部分:并发与延迟<===
#1、下载器总共最大处理的并发请求数,默认值16
#CONCURRENT_REQUESTS = 32

#2、每个域名能够被执行的最大并发请求数目,默认值8
#CONCURRENT_REQUESTS_PER_DOMAIN = 16

#3、能够被单个IP处理的并发请求数,默认值0,代表无限制,需要注意两点
#I、如果不为零,那CONCURRENT_REQUESTS_PER_DOMAIN将被忽略,即并发数的限制是按照每个IP来计算,而不是每个域名
#II、该设置也影响DOWNLOAD_DELAY,如果该值不为零,那么DOWNLOAD_DELAY下载延迟是限制每个IP而不是每个域
#CONCURRENT_REQUESTS_PER_IP = 16

#4、如果没有开启智能限速,这个值就代表一个规定死的值,代表对同一网址延迟请求的秒数
#DOWNLOAD_DELAY = 3

 

#===>第三部分:智能限速/自动节流:AutoThrottle extension<===
#一:介绍
from scrapy.contrib.throttle import AutoThrottle #http://scrapy.readthedocs.io/en/latest/topics/autothrottle.html#topics-autothrottle
设置目标:
1、比使用默认的下载延迟对站点更好
2、自动调整scrapy到最佳的爬取速度,所以用户无需自己调整下载延迟到最佳状态。用户只需要定义允许最大并发的请求,剩下的事情由该扩展组件自动完成


#二:如何实现?
在Scrapy中,下载延迟是通过计算建立TCP连接到接收到HTTP包头(header)之间的时间来测量的。
注意,由于Scrapy可能在忙着处理spider的回调函数或者无法下载,因此在合作的多任务环境下准确测量这些延迟是十分苦难的。 不过,这些延迟仍然是对Scrapy(甚至是服务器)繁忙程度的合理测量,而这扩展就是以此为前提进行编写的。


#三:限速算法
自动限速算法基于以下规则调整下载延迟
#1、spiders开始时的下载延迟是基于AUTOTHROTTLE_START_DELAY的值
#2、当收到一个response,对目标站点的下载延迟=收到响应的延迟时间/AUTOTHROTTLE_TARGET_CONCURRENCY
#3、下一次请求的下载延迟就被设置成:对目标站点下载延迟时间和过去的下载延迟时间的平均值
#4、没有达到200个response则不允许降低延迟
#5、下载延迟不能变的比DOWNLOAD_DELAY更低或者比AUTOTHROTTLE_MAX_DELAY更高

#四:配置使用
#开启True,默认False
AUTOTHROTTLE_ENABLED = True
#起始的延迟
AUTOTHROTTLE_START_DELAY = 5
#最小延迟
DOWNLOAD_DELAY = 3
#最大延迟
AUTOTHROTTLE_MAX_DELAY = 10
#每秒并发请求数的平均值,不能高于 CONCURRENT_REQUESTS_PER_DOMAIN或CONCURRENT_REQUESTS_PER_IP,调高了则吞吐量增大强奸目标站点,调低了则对目标站点更加”礼貌“
#每个特定的时间点,scrapy并发请求的数目都可能高于或低于该值,这是爬虫视图达到的建议值而不是硬限制
AUTOTHROTTLE_TARGET_CONCURRENCY = 16.0
#调试
AUTOTHROTTLE_DEBUG = True
CONCURRENT_REQUESTS_PER_DOMAIN = 16
CONCURRENT_REQUESTS_PER_IP = 16

 

#===>第四部分:爬取深度与爬取方式<===
#1、爬虫允许的最大深度,可以通过meta查看当前深度;0表示无深度
# DEPTH_LIMIT = 3

#2、爬取时,0表示深度优先Lifo(默认);1表示广度优先FiFo

# 后进先出,深度优先
# DEPTH_PRIORITY = 0
# SCHEDULER_DISK_QUEUE = 'scrapy.squeue.PickleLifoDiskQueue'
# SCHEDULER_MEMORY_QUEUE = 'scrapy.squeue.LifoMemoryQueue'
# 先进先出,广度优先

# DEPTH_PRIORITY = 1
# SCHEDULER_DISK_QUEUE = 'scrapy.squeue.PickleFifoDiskQueue'
# SCHEDULER_MEMORY_QUEUE = 'scrapy.squeue.FifoMemoryQueue'


#3、调度器队列
# SCHEDULER = 'scrapy.core.scheduler.Scheduler'
# from scrapy.core.scheduler import Scheduler

#4、访问URL去重
# DUPEFILTER_CLASS = 'step8_king.duplication.RepeatUrl'

 

#===>第五部分:中间件、Pipelines、扩展<===
#1、Enable or disable spider middlewares
# See http://scrapy.readthedocs.org/en/latest/topics/spider-middleware.html
#SPIDER_MIDDLEWARES = {
# 'Amazon.middlewares.AmazonSpiderMiddleware': 543,
#}

#2、Enable or disable downloader middlewares
# See http://scrapy.readthedocs.org/en/latest/topics/downloader-middleware.html
DOWNLOADER_MIDDLEWARES = {
# 'Amazon.middlewares.DownMiddleware1': 543,
}

#3、Enable or disable extensions
# See http://scrapy.readthedocs.org/en/latest/topics/extensions.html
#EXTENSIONS = {
# 'scrapy.extensions.telnet.TelnetConsole': None,
#}

#4、Configure item pipelines
# See http://scrapy.readthedocs.org/en/latest/topics/item-pipeline.html
ITEM_PIPELINES = {
# 'Amazon.pipelines.CustomPipeline': 200,
}

 

#===>第六部分:缓存<===
"""
1. 启用缓存
目的用于将已经发送的请求或相应缓存下来,以便以后使用

from scrapy.downloadermiddlewares.httpcache import HttpCacheMiddleware
from scrapy.extensions.httpcache import DummyPolicy
from scrapy.extensions.httpcache import FilesystemCacheStorage
"""
# 是否启用缓存策略
# HTTPCACHE_ENABLED = True

# 缓存策略:所有请求均缓存,下次在请求直接访问原来的缓存即可
# HTTPCACHE_POLICY = "scrapy.extensions.httpcache.DummyPolicy"
# 缓存策略:根据Http响应头:Cache-Control、Last-Modified 等进行缓存的策略
# HTTPCACHE_POLICY = "scrapy.extensions.httpcache.RFC2616Policy"

# 缓存超时时间
# HTTPCACHE_EXPIRATION_SECS = 0

# 缓存保存路径
# HTTPCACHE_DIR = 'httpcache'

# 缓存忽略的Http状态码
# HTTPCACHE_IGNORE_HTTP_CODES = []

# 缓存存储的插件
# HTTPCACHE_STORAGE = 'scrapy.extensions.httpcache.FilesystemCacheStorage'

新建抓取脚本

#导包
import scrapy
import os

#定义抓取类
class Test(scrapy.Spider):

#定义爬虫名称,和命令行运行时的名称吻合
name = "test"

#定义头部信息
haders = {
'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Ubuntu Chromium/73.0.3683.86 Chrome/73.0.3683.86 Safari/537.36'
}

#定义回调方法
def parse(self, response):
#将抓取页面保存为文件
page = response.url.split("/")[-2]
filename = 'test-%s.html' % page
if not os.path.exists(filename):
with open(filename, 'wb') as f:
f.write(response.body)
self.log('Saved file %s' % filename)


#匹配规则

content_left_div = response.xpath('//*[@id="content-left"]')
content_list_div = content_left_div.xpath('./div')

for content_div in content_list_div:
yield {
'author': content_div.xpath('./div/a[2]/h2/text()').get(),
'content': content_div.xpath('./a/div/span/text()').getall(),
}

#定义列表方法
def start_requests(self):
urls = [
'https://www.qiushibaike.com/text/page/1/',
'https://www.qiushibaike.com/text/page/2/',
]
for url in urls:
#如果想使用代理 可以加入代理参数 meta
#meta={'proxy': 'http://proxy.yourproxy:8001'}

#抓取方法
yield scrapy.Request(url=url, callback=self.parse,headers=self.haders)

执行抓取脚本 注意脚本名称和上文定义的name变量要吻合

scrapy crawl test

scrapy 中间件

下载器中间件是介于Scrapy的request/response处理的钩子框架,是用于全局修改Scrapy request和response的一个轻量、底层的系统。

开发代理中间件

在爬虫开发中,更换代理IP是非常常见的情况,有时候每一次访问都需要随机选择一个代理IP来进行。

中间件本身是一个Python的类,只要爬虫每次访问网站之前都先“经过”这个类,它就能给请求换新的代理IP,这样就能实现动态改变代理。

在创建一个Scrapy工程以后,工程文件夹下会有一个middlewares.py文件

在middlewares.py中添加下面一段代码:

import random
from scrapy.conf import settings

class ProxyMiddleware(object):

def process_request(self, request, spider):
proxy = random.choice(settings['PROXIES'])
request.meta['proxy'] = proxy

进入settings,开启中间件

DOWNLOADER_MIDDLEWARES = {
'AdvanceSpider.middlewares.ProxyMiddleware': 543,
}

配置好后运行爬虫,scrapy会在每次请求之前随机分配一个代理,可以请求下面的网址查看是否用了代理

http://exercise.kingname.info/exercise_middleware_ip

分布式爬虫

Scrapy-Redis是一个基于Redis的Scrapy分布式组件。它利用Redis对用于爬取的请求(Requests)进行存储和调度(Schedule),并对爬取产生的项目(items)存储以供后续处理使用。scrapy-redi重写了scrapy一些比较关键的代码,将scrapy变成一个可以在多个主机上同时运行的分布式爬虫。

具体部署和使用攻略:https://v3u.cn/Index_a_id_83

说白了,就是使用redis来维护一个url队列,然后scrapy爬虫都连接这一个redis获取url,且当爬虫在redis处拿走了一个url后,redis会将这个url从队列中清除,保证不会被2个爬虫拿到同一个url,即使可能2个爬虫同时请求拿到同一个url,在返回结果的时候redis还会再做一次去重处理,所以这样就能达到分布式效果,我们拿一台主机做redis 队列,然后在其他主机上运行爬虫.且scrapy-redis会一直保持与redis的连接,所以即使当redis 队列中没有了url,爬虫会定时刷新请求,一旦当队列中有新的url后,爬虫就立即开始继续爬

应对反爬

headers头文件 有些网站对爬虫反感,对爬虫请求一律拒绝,这时候我们需要伪装成浏览器,通过修改http中的headers来实现

headers = {
'Host': "bj.lianjia.com",
'Accept': "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
'Accept-Encoding': "gzip, deflate, sdch",
'Accept-Language': "zh-CN,zh;q=0.8",
'User-Agent': "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.87 Safari/537.36",
'Connection': "keep-alive",
}
p = requests.get(url, headers=headers)
print(p.content.decode('utf-8'))

伪造Cookie

模拟登陆

一般登录的过程都伴随有验证码,这里我们通过selenium自己构造post数据进行提交,将返回验证码图片的链接地址输出到控制台下,点击图片链接识别验证码,输入验证码并提交,完成登录

from selenium import webdriver
from selenium.webdriver.common.keys import Keys #
from selenium.webdriver.support.ui import WebDriverWait # WebDriverWait的作用是等待某个条件的满足之后再往后运行
from selenium.webdriver import ActionChains
import time
import sys
driver = webdriver.PhantomJS(executable_path='C:\PyCharm 2016.2.3\phantomjs\phantomjs.exe') # 构造网页驱动

driver.get('https://www.zhihu.com/#signin') # 打开网页
driver.find_element_by_xpath('//input[@name="password"]').send_keys('your_password')
driver.find_element_by_xpath('//input[@name="account"]').send_keys('your_account')
driver.get_screenshot_as_file('zhihu.jpg') # 截取当前页面的图片
input_solution = input('请输入验证码 :')
driver.find_element_by_xpath('//input[@name="captcha"]').send_keys(input_solution)
time.sleep(2)

driver.find_element_by_xpath('//form[@class="zu-side-login-box"]').submit() # 表单的提交 表单的提交,即可以选择登录按钮然后使用click方法,也可以选择表单然后使用submit方法
sreach_widonw = driver.current_window_handle # 用来定位当前页面
# driver.find_element_by_xpath('//button[@class="sign-button submit"]').click()
try:
dr = WebDriverWait(driver,5)
# dr.until(lambda the_driver: the_driver.find_element_by_xpath('//a[@class="zu-side-login-box"]').is_displayed())
if driver.find_element_by_xpath('//*[@id="zh-top-link-home"]'):
print('登录成功')
except:
print('登录失败')
driver.save_screenshot('screen_shoot.jpg') #截取当前页面的图片
sys.exit(0)
driver.quit() #退出驱动

代理ip

当爬取速度过快时,当请求次数过多时都面临ip被封的可能。因此使用代理也是必备的。

代理池的概念

抓取市面上所有免费代理网站的ip,比如西刺代理,快代理等

代理池维护存储 redis 因为代理ip生命周期很短,属于热数据,不适合持久化存储

使用时随机取出一个代理ip使用

使用request加代理

import requests
proxies = { "http": "http://10.10.1.10:3128",
"https": "http://10.10.1.10:1080",}
p = request.get("http://www.baidu.com", proxies = proxies)
print(p.content.decode('utf-8'))

抓取App端数据

使用Charles抓包

软件地址 https://www.charlesproxy.com/download/

为什么选择Charles 跨平台,方便好用,可以抓取Android应用也可以抓取Ios

可以抓取http https

抓取视频

使用三方库 you-get

配合Fiddler抓包来抓取视频流

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2020-02-25 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 爬虫常用库
  • 增量爬虫
  • Scrapy 相关
  • Scrapy整体架构
  • 数据流(流程,类似抓取任务生命周期)
  • 安装
  • scrapy 中间件
  • 分布式爬虫
  • 应对反爬
  • 伪造Cookie
  • 代理ip
    • 代理池的概念
    • 抓取App端数据
    • 抓取视频
    相关产品与服务
    云数据库 Redis
    腾讯云数据库 Redis(TencentDB for Redis)是腾讯云打造的兼容 Redis 协议的缓存和存储服务。丰富的数据结构能帮助您完成不同类型的业务场景开发。支持主从热备,提供自动容灾切换、数据备份、故障迁移、实例监控、在线扩容、数据回档等全套的数据库服务。
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档