scrapy实战笔记

一,基础
scrapy优势:异步IO,性能强;内置功能丰富(css,xpath);易扩展
爬虫简要步骤:URL分析,数据爬取分析逻辑开发,数据储存(数据库),反爬虫策略。
注意事项:注意不要违法(关闭robot协议,不违法)
其他相关知识:virtualenv,正则,编码(ASCII, unicode, UTF-8)
字符串编码知识:

scrapy实战笔记
文章图片
WX20200204-151821@2x.png
WX20200204-160154@2x.png 二,xpath
1,xpath语法
respone.xpath返回的是select元素,可以继续使用xpath.
select元素的extract()方法,提取对象的值的数组,由于一般取数组的第一项,故可以使用extract_first()
例子:respone.xpath().extract()[0] <===> respone.xpath().extract_first()
比较:前者需要异常处理(数组为空的情况),后者有默认返回None,所以优先使用后者

  • xpath中使用XSLT元素和函数,例如:response.xpath('//h1/text()'),其中text()就是XSLT函数
  • 元素有多个class时,仅仅写//span[@class="xxx"],可能匹配不到,可以写//span[contains(@class, 'xxx')]
    -尽量通过class或者id选择元素,不要使用绝对选择,比如/html/body/div[3]/h1/div/span
    有的元素是动态JS插入的,绝对选择很容易出错
2,scrapy shell url
测试xpath可以在命令行使用如上命令,比打断点调试快
3,css选择器
例子:response.css('.xxx h1::text').extract()
提取class为xxx的元素中的h1中的文本
还有很多其他尾类选择器,常用的如::attr(href),获取a标签的href属性
三,url提取
1,运用urllib中的parse
parse.urljoin(baseurl, target):会自动提取baseURL中的域名与target结合
2,scrapy.http中的Request
使用这个Request可以将新获取的url传递给scrapy,参数有url, callback,还可以增加meta,给callback传餐,获取meta参数,使用response.meta['xxx'],或者使用字典的get方法,避免错误
四,items??格式化 和 pipeline??数据存储
1,item中定义要获取的数据字段,然后在spider中创建item类的实例,并讲相关的值以字典的形式赋值给item实例。
调用yield item实例,这些字段就会在pipeline中处理
2,配置pipeline,以及优先级,越小越先进入pipeline处理
每个pipeline要return item,最后将数据存储到DB,或者使用codecs包,保存到文件
3,item loader
add_css(‘name', '规则')
add_xpath(‘name', '规则')
add_value(‘name', 值)
item_loader.load_item() 解析规则,生成item实例
注意:生成的item实例,每个字段的值都是list,而且没有特异化处理
解决:在 xx = scrapy.field() 中用scrapy.loader.processors中的MapCompose预处理数据,接收多个函数,依次处理
五,模拟登陆
使用requests库和cookie
try import cookielib except: import http.cookiejar as cookie # python3

六,反爬虫
1,UA
不建议使用fake_useragent,不好用
在网上找个UA的list,随机取就好
2,IP代理(通过代理服务器)(西次IP代理)
在中间件:request.meta['proxy'] = '西次的IP代理'
爬取所有高密的IP代理,构造IP代理池
GitHub ---> scrapy proxy 现成的轮子
3,验证码识别 (略过,后面补)
人工打码 && 在线打码
七,动态网站爬取selenium
selenium英文文档
selenium中文文档
其实这一块看文档足够,简单,而且文档比较好
Chromedriver使用教程
selenium适用于自动化测试,完全满足爬取动态网页,模拟点击,模拟登陆等功能
下载Chromedriver,编写脚本模拟浏览器加载,获取浏览器解析后的代码,即可。

scrapy实战笔记
文章图片
企业微信20200212050144.png
1,常用方法
browser.find_elemnt_by_xxxx() xxx有css,xpath,node,id等等多种方法
browser.find_elemnt_by_xxxx().send_keys() 如果选取的是input,这个方法就是输入值
browser.find_elemnt_by_xxxx().click() 模拟点击
browser.execute_script(‘window.scrollTo(0, document.body.scrollHeight); var a=10; ') 运行JS代码,做一些滚动等动作,便于爬取微博这种滚动加载的页面
2,不加载图片
当不需要加载图片时,使用此功能可以提高爬虫速度
这个方法文档中并没有,可以去读源码,结合文档自己分析
from selenium import webdriver prefs = { "profile.managed_default_content_settings.images":2 }chrome_opt = webdriver.ChromeOptions() chrome_opt.add_experimental_option("prefs", prefs)browser = webdriver.Chrome(executable_path="path", chrome_opt=chrome_opt) browser.get("url")

3,selenium集成到scrapy
通过scrapy的middleware中的process_request,使request通过selenium的get来请求,最后return 一个scrapy.http中的HtmlResponse即可(scrapy就不会再处理了)
代码如下:通过注释,已经解释了为什么这么写,这么写的好处
class DigeSpiderSpiderMiddleware(object): # Not all methods need to be defined. If a method is not defined, # scrapy acts as if the spider middleware does not modify the # passed objects. def __init__(self): # 每个爬虫只开一次浏览器 # 放到spider中,保证了每个 有需要的spider单独开浏览器,不影响其他spider,还可以提高并发效率 self.browser = webdriver.Chrome(executable_path='/Users/chaos/desktop/chromedriver') # super(DigeSpiderSpiderMiddleware, self).__init__() dispatcher.connect(self.spider_closed, signals.spider_closed)def spider_closed(self): # 通过信号与槽,当spider关闭时,关闭浏览器 self.browser.quit()class chrome_filter(object):def process_request(self, request, spider): if spider.name == 'price_info_spider': spider.browser.get(request.url) time.sleep(2) spider.browser.execute_script('window.scrollTo(0, document.body.scrollHeight); var a=10; ') # 向下滚动页面 time.sleep(2) return HtmlResponse(url=spider.browser.current_url, body=spider.browser.page_source, encoding='utf-8')

有待提升部分:time的sleep降低了scrapy的效率,最好能改写为异步的。这不敷需要重写scrapy的downloader。我暂不考虑
八,redis缓存打造分布式爬虫
【scrapy实战笔记】原理:使用redis缓存多个服务器爬虫的url去重逻辑和request队列
优势:多个服务器(IP),速度与安全都极大提升
九,扩展,elasticsearch打造企业级搜索引擎

    推荐阅读