爬虫学习笔记
爬虫的概念
模拟浏览器发起请求,获取响应数据
爬虫的流程
url--->响应内容--->抓取数据--->保存到数据库
爬虫要根据当前URL地址对应的响应为准,当前URL地址的elements的内容和URL的响应不一样
当前URL地址对应的响应中
其他URL地址对应的响应中
比如ajax请求中
js生成的
部分数据在响应中
全部通过js生成
URL组成部分
形式 scheme://host[:port#]/path/…/[?query-string][#anchor]
scheme:协议(例如:http, https, ftp)
host:服务器的IP地址或者域名
port:服务器的端口(如果是走协议默认端口,80 or 443)
path:访问资源的路径
query-string:参数,发送给http服务器的数据
anchor:锚(跳转到网页的指定锚点位置)
http://localhost:4000/file/part01/1.2.html
http://item.jd.com/11936238.html#product-detail
requests中的解决编解码的方法
response.content.decode()
response.content.decode('gbk')
response.text
使用代理IP
-准备一堆的ip地址,随机选择一个ip使用
-如何随机选择代理ip,让使用次数比较少的有更大可能被用到
-{‘ip’:ip,'times':0}
-[{},{},{}]对这个ip列表进行遍历
Requests相关
http://docs.python-requests.org/zh_CN/latest/user/quickstart.html
正则使用的注意点
-re.findall("a(.*?)","str),能够返回括号中的内容,括号前后的内容祈祷定位和过滤的效果
-原始字符串r,待匹配字符串中有反斜杠\的时候,会让转义效果失效
-点号.默认匹配不到换行符\n
-\s能匹配到空白字符,不仅仅包含空格,还有\t|\r\n
Python compile() 函数
将一个正则表达式编译成python可识别的模式,这个模式的方法有findall(),sub()
描述
compile() 函数将一个字符串编译为字节代码。
语法
以下是 compile() 方法的语法:
compile(source, filename, mode[, flags[, dont_inherit]])
参数
- source – 字符串或者AST(Abstract Syntax Trees)对象。。
- filename – 代码文件名称,如果不是从文件读取代码则传递一些可辨认的值。
- mode – 指定编译代码的种类。可以指定为 exec, eval, single。
- flags – 变量作用域,局部命名空间,如果被提供,可以是任何映射对象。。
- 1).re.I(re.IGNORECASE): 忽略大小写
- 2).re.M(MULTILINE): 多行模式,改变’^’和’$’的行为
- 3).re.S(DOTALL): 点任意匹配模式,改变’.’的行为
- 4).re.L(LOCALE): 使预定字符类 \w \W \b \B \s \S 取决于当前区域设定
- 5).re.U(UNICODE): 使预定字符类 \w \W \b \B \s \S \d \D 取决于unicode定义的字符属性
- 6).re.X(VERBOSE): 详细模式。这个模式下正则表达式可以是多行,忽略空白字符,并可以加入注释
- flags和dont_inherit是用来控制编译源码时的标志
返回值
返回表达式执行结果。
xpath学习重点
实现爬虫的套路
- 准备url
- 准备start_url
- url地址规律不明显,总数不确定
- 通过代码提取下一页的url
- xpath
- 寻找url地址,部分参数在当前的响应中(比如,当前页码数和总页码数在当前响应中)
- 准备url_list
- 页码总数明确
- url地址规律明显
- 发送请求,获取响应
- 添加随机的User-Agent,反反爬虫
- 添加随机的代理ip
- 在对方判断出我们是爬虫后,应该添加更多的headers字段包括cookie
- cookie的处理可以使用session解决
- 准备一堆的cookie,组成cookie池
- 如果不登录
- 准备刚开始能够成功请求对方网站的cookie,即接收对方设置在response的cookie
- 下一次请求的时候,使用之前的列表中的cookie来请求
- 如果登陆
- 准备多个帐号
- 使用程序获取多个帐号的cookie
- 之后请求登陆之后才能访问的网站随机的选择cookie
- 提取数据
- 确定数据的位置
- 如果数据在当前的url地址中
- 提取的是列表页的数据
- 直接请求列表页的url地址,不用进入详情页
- 提取的是详情页数据
- 1、确定url
- 2、发送请求
- 3、提取数据
- 4、返回保存
- 如果数据不在当前的url地址中
- 在其他的响应中,寻找数据的位置
- 1、从network中从上到下找
- 2、使用Chrome中的过滤条件,选择除了js,css,哦买噶,之外的按钮
- 3、使用Chrome的search all file,搜索数字和英文
- 数据的提取
- xpath,从html中提取整块的数据,先分组,之后每一组再提取
- re,提取max_time,price,html中的json字符串
- json
- 数据保存
- 保存在本地,text,json,csv
- 保存在数据库
“如今你的气质里,藏着你走过的路,读过的书和爱过的人。” ——《卡萨布兰卡》
selenium和phantomJS
# 用户名
username = 'dotcoo'
# 密码
password = 'dotcoo'
# 软件ID,开发者分成必要参数。登录开发者后台【我的软件】获得!
appid = 4916
# 软件密钥,开发者分成必要参数。登录开发者后台【我的软件】获得!
appkey = '7b392d65faf3ca3167be1ae94448e3e5'
MongoDB
mongodb插入数据
- db.collection.insert({}),_id存在会报错
- db.collection.save({}),_id存在会更新
mongodb的更新操作
- db.collection.update({name:”ming”},{name:”hong”}),把ming更换为hong
- db.collection.update({name:”hong”},{$set:{name:”ling”}}), 指定把hong替换为ling
- {multi:true}更换多条
删除
- db.collection.remove({name:”hong”},{justOne:true})
- 默认会删除多条满足的数据,{justOne:true}只删除一条
count方法
- db.collection.find().count()
- db.collection.count({})
投影
- 选择返回结果的字段
- db.collection.find({条件},{name:1,_id:0})
- 1、_id默认会显示。置为0不显示
- 2、除了_id之外的其它字段,需要显示则写1,不显示不写,不能写0
group的注意点
- $group 对应的字典中有几个键,结果中就有几个键
- 分组依据需要放到_id 后面
- 取不同字段的值需要使用,例如”gender,$age”
- 取字典嵌套的字典中的值时$_id.country
- 能够同时按照多个健将进行分组 {group:{_id:{country:" group:{_id:{country:" country",province:"$province”}}}
- 结果是:{_id:{country:”“,province:”“}}
mongodb mysql redis的区别和使用场景
- mysql是关系型数据库,支持事物
- mongodb,redis非关系型数据库,不支持事物
- mysql,mongodb,redis的使用根据如何方便进行选择
- 希望速度快的时候,选择mongodb或者是redis
- 数据量过大的时候,选择频繁使用的数据存入redis,其他的存入mongodb
- mongodb不用提前建表建数据库,使用方便,字段数量不确定的时候使用mongodb
- 后续需要用到数据之间的关系,此时考虑mysql
爬虫数据去重,实现增量式爬虫
- 使用数据库建立关键字段(一个或者多个)建立索引进行去重
- 根据url地址进行去重
- 使用场景:
- url地址对应的数据不会变的情况,url地址能够唯一判别一个条数据的情况
- 思路
- url存在redis中
- 拿到url地址,判断url在redis的url的集合中是够存在
- 存在:说明url已经被请求过,不再请求
- 不存在:url地址没有被请求过,请求,把该url存入redis的集合中
- 布隆过滤器
- 使用多个加密算法加密url地址,得到多个值
- 往对应值的位置把结果设置为1
- 新来一个url地址,一样通过加密算法生成多个值
- 如果对应位置的值全为1,说明这个url地址已经抓过
- 否则没有抓过,就把对应位置的值设置为1
- 根据数据本省进行去重
- 选择特定的字段,使用加密算法(md5,sha1)讲字段进行假面,生成字符串,存入redis的集合中
- 后续新来一条数据,同样的方法进行加密,如果得到的字符串在redis中存在,说明数据存在,对数据进行更新,否则说明数据不存在,直接插入
组成部分介绍:
- Scrapy Engine:
负责组件之间数据的流转,当某个动作发生时触发事件
- Scheduler:
接收requests,并把他们入队,以便后续的调度
- Downloader:
负责抓取网页,并传送给引擎,之后抓取结果将传给spider
- Spiders:
用户编写的可定制化的部分,负责解析response,产生items和URL
- Item Pipeline:
负责处理item,典型的用途:清洗、验证、持久化
- Downloader middlewares:
位于引擎和下载器之间的一个钩子,处理传送到下载器的requests和传送到引擎的response(若需要在Requests到达Downloader之前或者是responses到达spiders之前做一些预处理,可以使用该中间件来完成)
- Spider middlewares:
位于引擎和抓取器之间的一个钩子,处理抓取器的输入和输出
(在spiders产生的Items到达Item Pipeline之前做一些预处理或response到达spider之前做一些处理)