共计 3460 个字符,预计需要花费 9 分钟才能阅读完成。
最近这两周在忙着给公司爬一点数据,更文的速度有一点下降,预计今天就爬完了,总结总结经验。
其实之前我司是有专门做爬虫的,不用前端这边出人干活。后来那人离职了,有可能就没有爬虫这方面的需求了。突然又有了一些,前端这边出人做一下。老大说用 py
做,前期先调研一下。
原理
爬虫其实原理上很简单,我们 == 客户端 , 他们 == 服务端 。
客户端发送请求 req
,服务端返回响应 rsp
。拿到响应之后解析数据,入库,就完事了。
请求数据 req
一般来说请求分为两种,拉数据 get
比较多。
偶尔部分接口需要登录,那就是多带 cookie
或者 headers
。
其实还有一部分工作就是 分析入参。
-
get
参数拼接在url
上 -
post
参数放在body
里
响应数据 rsp
返回数据大体上是两种
-
JSON
一般来说,通过 抓包 或者说 network 工具。我们找到了服务端的接口,那么我直接访问这个接口即可。
本文第一个重点来了:切换到移动端再查一遍,往往有不一样的收获,一般来说PC
和M
端的进度不了,有可能都不是一个项目组,所以实现方式就会有差别。 -
html
比较坑的一种方式,因为没有找到JSON
接口。无奈只能走解析HTML
的路子。
调研
-
Node
之前给后台搭架子的时候使用过,主要功能点如下:- 自动登录,(拿
headers、cookie
) - 存储本地,每次请求带上
token
- 启动代理服务
- 自动登录,(拿
-
py
老大说要用这个东西。咨询了一下其他朋友,说可以使用下面的工具。-
requests
+beautifulSoup
使用起来其实就是requests
发请求,beautifulSoup
解析HTML
。比较原始。 -
scrapy
一个爬虫的框架。我在这里学的 www.scrapyd.cn。实现上比较完整,可以设置请求间隔,随机ua
等功能。
-
-
前端实现
我一个铁头娃,怎么能轻言放弃?身为一个 前端 er,还是这些api
让我更加亲切-
XHR
发请求利器,打开对方页面,cookie
啥的都自带。无敌就是这么寂寞 。
其实还可以找到对方请求发起的位置,打个断点,把对方内部的代码绑定到全局,这样一些内部逻辑什么的也都没问题。
而且还 JSON HTML 通吃。 -
iframe
针对HTML
类型的处理。同域的情况下,也无敌好吗?-
HTML
获取DOM
节点? - 甚至可以取
window
上的对象。vue SSR 你感觉到了威胁吗?
-
-
-
网上其他服务商提供的接口(真香啊)。有免费的有收费的,一般免费的限量。
- 比如抖音热度?
- 比如各类音乐的歌单和作品?
- IP 查询
- 天气查询
好了上面说了那么多,建议老大限制,我选择了 scrapy
。
scrapy
scrapy
是一个网页爬虫框架,神马叫做爬虫,如果没听说过,那就:内事不知问度娘,外事不决问谷歌,百度或谷歌一下吧!……(这里的省略号代表scrapy
很牛逼,基本神马都能爬,包括你喜欢的苍老师……这里就不翻译了)
看到这个骚的飞起的介绍了吗?没错,我就是在上面学的。scrapy 中文站。接下来我就介绍一下我认为对于新手比较关注的东西
scrapy HTML
scrapy
处理器中的 response
标识你拿到的 rsp 上面自带了一些方法,一般来说需要关注的只有两个
css 选择器
quote.css('span.text::text').extract_first()
中的 'span.text::text'
眼熟吗?
没错,就是我们常用的选择器。通过这个 api
,我们可以把我们想要的数据,限时在一个很小的范围,然后拿字符串即可。
啥?你说你不会 css
选择器?前端培训 - 初级阶段(5 – 8)-CSS 选择器(基本、层级、属性、伪类、伪状态)
-
extract()
函数提取列表 -
extract_first()
代表提取第一个元素。基本等价于extract()[0]
-
::text
选择其中的文字 -
::attr(href)
提取属性
xpath
quote.xpath('span/small/text()').extract_first()
文档,这个我不会,我也没看
scrapy JSON
import json
使用这个类库解析如:json.loads(response.body.decode('utf-8'))
scrapy 请求方式
get
import urllib
可以用来给中文字符 encode
yield scrapy.FormRequest(
url,
method = 'GET',
headers = self.headers,
formdata={},
callback = self.parse_list,
dont_filter = True,
meta = {'offset': 0,})
post
数据放入 formdata
传递即可。
yield scrapy.FormRequest(
url,
method = 'POST',
headers = self.headers,
formdata={},
callback = self.parse_list,
dont_filter = True,
meta = {'offset': 0,})
给回调模块带参数
meta = {'offset': 0,}
如下方式接收
disstid = response.meta['offset']
外部传参方式
scrapy crawl argsSpider -a tag= 爱情
内部是使用如下命令可以接收到。
def start_requests(self):
url = 'http://lab.scrapyd.cn/'
tag = getattr(self, 'tag', None) # 获取 tag 值,也就是爬取时传过来的参数
scrapy mysql
大数据那边说爬回来的数据要入库。
-
scrapyMysql/scrapyMysql/items.py
编写对应入库字段。import scrapy class ScrapymysqlItem(scrapy.Item): # define the fields for your item here like: # name = scrapy.Field() tag = scrapy.Field() # 标签字段 cont = scrapy.Field() # 名言内容 pass
-
scrapyMysql/scrapyMysql/spiders/inputMysql.py
写爬虫处理操作时,入库item = ScrapymysqlItem() # 实例化 item 类 for v in mingyan: # 循环获取每一条名言里面的:名言内容、作者、标签 item['cont'] = v.css('.text::text').extract_first() # 提取名言 tags = v.css('.tags .tag::text').extract() # 提取标签 item['tag'] = ','.join(tags) # 数组转换为字符串 yield item # 把取到的数据提交给 pipline 处理
-
编写 MySQL 存储插件:
MySQLPipeline.py
import pymysql.cursors class MySQLPipeline(object): def __init__(self): # 连接数据库 self.connect = pymysql.connect( host='127.0.0.1', # 数据库地址 port=3306, # 数据库端口 db='scrapyMysql', # 数据库名 user='root', # 数据库用户名 passwd='root', # 数据库密码 charset='utf8', # 编码方式 use_unicode=True) # 通过 cursor 执行增删查改 self.cursor = self.connect.cursor() def process_item(self, item, spider): self.cursor.execute("""insert into mingyan(tag, cont) value (%s, %s)""", # 纯属 python 操作 mysql 知识,不熟悉请恶补 (item['tag'], # item 里面定义的字段和表字段对应 item['cont'],)) # 提交 sql 语句 self.connect.commit() return item # 必须实现返回
-
settings 启动 MySQLPipline 组件
ITEM_PIPELINES = {'scrapyMysql.MySQLPipline.MySQLPipeline': 300,}
总结一下
到现在,我们已经完成了所有基础知识的积累。遇到不会我们去里看?。
总结一下需要注意点的
- 切换 PC 和 M 端,寻找可行的方案
- 注意节制(部分容易限量)
- python 编码问题(真的好烦)
- 网上提供的那个
mysql
库和我的不合,我换了一个MySQLdb
- 第三方的接口是真香
微信公众号