1、接触过几种爬虫模块
urllib requests
2、robots协议是什么?
网站有一些数据不想被爬虫程序爬取,可以编写robots协议文件,明确指明哪些内容可以爬取哪些不可以爬取。
在Scrapy框架中在settings.py文件中使用了硬性语法对该协议进行了生效
3、如何处理验证码?
使用三方的打码平台比如:云打码平台、打码兔,可以用来处理验证码。
4、掌握几种数据解析的方式?
re、xpath(最常用)、bs4(python独有)
5、如何爬取动态加载的页面数据?
selenium; ajax:抓包工具抓取异步发起的请求(url)
6、接触过哪些反爬机制?如何处理?
robots协议、UA、封IP、验证码、动态数据加载、数据加密、token
处理:
配置不遵守robots协议、伪装User-Agent、代理IP更换、打码平台对验证码识别、
selenium处理或者使用抓包工具去抓取动态加载的AJAX请求数据包、
按照已知的各种加密方式进行解密、去前台页面进行token值的查找手动放入请求携带的参数中。
7、在Scrapy中接触过几种爬虫类?
Spider、CrawlSpider(链接提取器和规则解析器)、RedisCrawlSpider、RedisSpider
8、如何实现分布式流程?
必须要通过scrapy-redis组件来实现,可以由RedisCrawlSpider、RedisSpider这两种类分别实现。
9.简述 requests模块的作用及基本使用?
Requests 自称 "HTTP for Humans",说明使用更简洁方便。
Requests支持HTTP连接保持和连接池,支持使用cookie保持会话,支持文件上传,支持自动确定响应内容的编码,
支持国际化的 URL 和 POST 数据自动编码。
10、requests模块参数,data与json参数的区别?
在通过requests.post()进行POST请求时,传入报文的参数有两个,一个是data,一个是json。
data与json既可以是str类型,也可以是dict类型。
区别:
1、不管json是str还是dict,如果不指定headers中的content-type,默认为application/json
2、data为dict时,如果不指定content-type,默认为application/x-www-form-urlencoded,相当于普通form表单提交的形式
3、data为str时,如果不指定content-type,默认为application/json
4、用data参数提交数据时,request.body的内容则为a=1&b=2的这种形式,用json参数提交数据时,request.body的内容则为'{"a": 1, "b": 2}'的这种形式
11、简述 beautifulsoup模块的作用及基本使用?
和 lxml 一样,Beautiful Soup 也是一个HTML/XML的解析器,主要的功能也是如何解析和提取 HTML/XML 数据。
lxml 只会局部遍历,而Beautiful Soup 是基于HTML DOM的,会载入整个文档,解析整个DOM树,因此时间和内存开销都会大很多,所以性能要低于lxml。
12、简述 seleninu模块的作用及基本使用?
Selenium 可以根据我们的指令,让浏览器自动加载页面,获取需要的数据,甚至页面截屏,或者判断网站上某些动作是否发生。
Selenium 自己不带浏览器,不支持浏览器的功能,它需要与第三方浏览器结合在一起才能使用。
13、scrapy框架中各组件的工作流程?
Scrapy Engine: 这是引擎,负责Spiders、ItemPipeline、Downloader、Scheduler中间的通讯,信号、数据传递等等
Scheduler(调度器): 它负责接受引擎发送过来的requests请求,并按照一定的方式进行整理排列,入队、并等待Scrapy Engine(引擎)来请求时,交给引擎。
Downloader(下载器):负责下载Scrapy Engine(引擎)发送的所有Requests请求,并将其获取到的Responses交还给Scrapy Engine(引擎),由引擎交给Spiders来处理
Spiders:它负责处理所有Responses,从中分析提取数据,获取Item字段需要的数据,并将需要跟进的URL提交给引擎,再次进入Scheduler(调度器)
Item Pipeline:它负责处理Spiders中获取到的Item,并进行处理,比如去重,持久化存储(存数据库,写入文件,总之就是保存数据用的)
Downloader Middlewares(下载中间件):你可以当作是一个可以自定义扩展下载功能的组件
Spider Middlewares(Spider中间件):你可以理解为是一个可以自定扩展和操作引擎和Spiders中间‘通信‘的功能组件
(比如进入Spiders的Responses;和从Spiders出去的Requests)
14、在scrapy框架中如何设置代理(两种方法)?
一.使用中间件DownloaderMiddleware进行配置
1.在Scrapy工程下新建“middlewares.py”
# Importing base64 library because we'll need it ONLY in case if the proxy we are going to use requires authentication
import base64
# Start your middleware class
class ProxyMiddleware(object):
# overwrite process request
def process_request(self, request, spider):
# Set the location of the proxy
request.meta['proxy'] = "http://YOUR_PROXY_IP:PORT"
# Use the following lines if your proxy requires authentication
proxy_user_pass = "USERNAME:PASSWORD"
# setup basic authentication for the proxy
encoded_user_pass = base64.encodestring(proxy_user_pass)
request.headers['Proxy-Authorization'] = 'Basic ' + encoded_user_pass
2.在项目配置文件里(./pythontab/settings.py)添加
DOWNLOADER_MIDDLEWARES = {
'scrapy.contrib.downloadermiddleware.httpproxy.HttpProxyMiddleware': 110,
'pythontab.middlewares.ProxyMiddleware': 100,
}
注意:
1.proxy一定是要写号http://前缀
2.如果代理有用户名密码等就需要在后面再加上一些内容
二.直接在爬虫程序中设置proxy字段
可以直接在自己具体的爬虫程序中设置proxy字段,直接在构造Request里面加上meta字段即可
class QuotesSpider(scrapy.Spider):
name = "quotes"
def start_requests(self):
urls = [
'http://quotes.toscrape.com/page/1/',
'http://quotes.toscrape.com/page/2/',
]
for url in urls:
yield scrapy.Request(url=url, callback=self.parse, meta={'proxy': 'http://proxy.yourproxy:8001'})
def parse(self, response):
for quote in response.css('div.quote'):
yield {
'text': quote.css('span.text::text').extract_first(),
'author': quote.css('span small::text').extract_first(),
'tags': quote.css('div.tags a.tag::text').extract(),
}
--------------
import scrapy
class ProxySpider(scrapy.Spider):
name = 'proxy'
allowed_domains = ["httpbin.org"]
def start_requests(self):
url = 'http://httpbin.org/get'
proxy = '127.0.0.0:8000'
proxies = ""
if url.startswith("http://"):
proxies = "http://"+str(proxy)
elif url.startswith("https://"):
proxies = "https://"+str(proxy)
#注意这里面的meta={'proxy':proxies},一定要是proxy进行携带,其它的不行,后面的proxies一定 要是字符串,其它任何形式都不行
yield scrapy.Request(url, callback=self.parse,meta={'proxy':proxies})
def parse(self,response):
print(response.text)
15、scrapy框架中如何实现大文件的下载?
利用scrapy下载大量大尺寸图片及视频时有时会报错,显示放弃重试
原因:
这是由于scrapy并发请求过多,默认情况下会同时下载16个文件,而连接时间默认超过三分钟就会丢失。
就是说如果三分钟之内你的网速没法支持你同时下载完16个文件的话就会造成这个问题。
解决方法:
在settings.py中将默认并发连接数调小或者将timeout时间调大
CONCURRENT_REQUESTS = 2
DOWNLOAD_TIMEOUT=1800
此时并发请求被调成2, 等待时间被1800秒,一般的小视频和图片是没有问题了。
16、scrapy中如何实现限速?
自动限速:
限制爬虫速度,对对方服务器友好些,防止被识别
在setting.py开启相关扩展:
自动限速设定:
AUTOTHROTTLE_ENABLED = True
设定爬取速度:
DOWNLOAD_DELAY = 1 #单位为秒
17、scrapy中如何实现暂定爬虫?
1.进入到scrapy项目里
2、在scrapy项目里创建保存记录信息的文件 zant/001
3、执行命令:
scrapy crawl 爬虫名称 -s JOBDIR=保存记录信息的路径
如:scrapy crawl cnblogs -s JOBDIR=zant/001
执行命令会启动指定爬虫,并且记录状态到指定目录
爬虫已经启动,我们可以按键盘上的ctrl+c停止爬虫,停止后我们看一下记录文件夹,会多出3个文件,
其中的requests.queue文件夹里的p0文件就是URL记录文件,这个文件存在就说明还有未完成的URL,当所有URL完成后会自动删除此文件
当我们重新执行命令:scrapy crawl cnblogs -s JOBDIR=zant/001 时爬虫会根据p0文件从停止的地方开始继续爬取。
18、scrapy中如何进行自定制命令?
【同时运行多个scrapy爬虫的几种方法(自定义scrapy项目命令)】
1、创建commands目录
mkdir commands
注意:commands和spiders目录是同级的
2、在commands下面添加一个文件crawlall.py
这里主要通过修改scrapy的crawl命令来完成同时执行spider的效果。
from scrapy.commands import ScrapyCommand
from scrapy.crawler import CrawlerRunner
from scrapy.utils.conf import arglist_to_dict
class Command(ScrapyCommand):
requires_project = True
def syntax(self):
return '[options]'
def short_desc(self):
return 'Runs all of the spiders'
def add_options(self, parser):
ScrapyCommand.add_options(self, parser)
parser.add_option("-a", dest="spargs", action="append", default=[], metavar="NAME=VALUE",
help="set spider argument (may be repeated)")
parser.add_option("-o", "--output", metavar="FILE",
help="dump scraped items into FILE (use - for stdout)")
parser.add_option("-t", "--output-format", metavar="FORMAT",
help="format to use for dumping items with -o")
def process_options(self, args, opts):
ScrapyCommand.process_options(self, args, opts)
try:
opts.spargs = arglist_to_dict(opts.spargs)
except ValueError:
raise UsageError("Invalid -a value, use -a NAME=VALUE", print_help=False)
def run(self, args, opts):
#settings = get_project_settings()
spider_loader = self.crawler_process.spider_loader
for spidername in args or spider_loader.list():
print "*********cralall spidername************" + spidername
self.crawler_process.crawl(spidername, **opts.spargs)
self.crawler_process.start()
self.crawler_process.spider_loader.list()方法获取项目下所有的spider,然后利用self.crawler_process.crawl运行spider
3、commands命令下添加__init__.py文件
touch __init__.py
注意:这一步一定不能省略。
cnblogs.commands为命令文件目录,crawlall为命令名。
4. 在settings.py中添加配置:
COMMANDS_MODULE = 'cnblogs.commands'
5. 运行命令scrapy crawlall
19、scrapy中如何实现的记录爬虫的深度?
通过在settings.py中设置DEPTH_LIMIT的值可以限制爬取深度,这个深度是与start_urls中定义url的相对值。
20、scrapy中的pipelines工作原理?
pipelines文件实现了一个item pipieline类,和scrapy的item pipeline是同一个对象,
通过从settings中拿到我们配置的REDIS_ITEMS_KEY作为key,
把item串行化之后存入redis数据库对应的value中(这个value可以看出出是个list,我们的每个item是这个list中的一个结点),
这个pipeline把提取出的item存起来,主要是为了方便我们延后处理数据。
21、scrapy的pipelines如何丢弃一个item对象?
//TODO
22、简述scrapy中爬虫中间件和下载中间件的作用?
下载中间件:
下载中间件是处于引擎(crawler.engine)和下载器(crawler.engine.download())之间的一层组件,可以有多个下载中间件被加载运行。
1.当引擎传递请求给下载器的过程中,下载中间件可以对请求进行处理 (例如增加http header信息,增加proxy信息等);
2.在下载器完成http请求,传递响应给引擎的过程中, 下载中间件可以对响应进行处理(例如进行gzip的解压等)
Spider中间件(Middleware):
下载器中间件是介入到Scrapy的spider处理机制的钩子框架,可以添加代码来处理发送给 Spiders 的response及spider产生的item和request。
23、scrapy-redis组件的作用?
实现分布式抓取
24、scrapy-redis组件中如何实现的任务的去重?
原理:
在分布式爬取时,会有master机器和slave机器,其中,master为核心服务器,slave为具体的爬虫服务器。
在master服务器上搭建一个redis数据库,并将要抓取的url存放到redis数据库中,所有的slave爬虫服务器在抓取的时候从redis数据库中获取链接,
由于scrapy_redis自身的队列机制,slave获取的url不会相互冲突,然后抓取的结果最后都存储到数据库中。
master的redis数据库中还会将抓取过的url的指纹存储起来,用来去重。相关代码在dupefilter.py文件中的request_seen()方法中可以找到。
去重问题:
dupefilter.py 里面的源码:
def request_seen(self, request):
fp = request_fingerprint(request)
added = self.server.sadd(self.key, fp)
return not added
去重是把 request 的 fingerprint 存在 redis 上,来实现的。
25、scrapy-redis的调度器如何实现任务的深度优先和广度优先?
//TODO
26、假设有如下两个list:a = ['a', 'b', 'c', 'd', 'e'],b = [1, 2, 3, 4, 5],
将 a 中的元素作为 key,b 中元素作为 value,将 a,b 合并为字典。
a = ['a', 'b', 'c', 'd', 'e']
b = [1, 2, 3, 4, 5]
zip1 = zip(a,b)
# print(zip1) #<zip object at 0x000002984CB6CCC8>
# print(list(zip1))
d = {}
for i in zip1:
d[i[0]] = i[1]
print(d) #{'a': 1, 'b': 2, 'c': 3, 'd': 4, 'e': 5}
27、爬取数据后使用哪个数据库存储数据的,为什么?
有规则的数据可以存入 MySQL 中,但是要注意抓取内容出现缺失的情况
不规则的数据存储在 MongoDB 中,直接将数据存入再进行数据清洗