爬虫爬 JSON HTML 数据
转载自 SegmentFault
最近这两周在忙着给公司爬一点数据,更文的速度有一点下降,预计今天就爬完了,总结总结经验。
其实之前我司是有专门做爬虫的,不用前端这边出人干活。后来那人离职了,有可能就没有爬虫这方面的需求了。突然又有了一些,前端这边出人做一下。老大说用 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 -
第三方的接口是真香
微信公众号
原文:SegmentFault