一个小爬虫:获取Kindle的图书排行榜
本程序抓取在linux和Mac上是没什么问题的,不过windows会遇到编码问题,暂时没有心情来处理这个bug,就是这么任性~
目标在这里:
获取Amazon Kindle的排行榜网址
library(XML)URL = paste0("http://www.amazon.cn/gp/bestsellers/digital-text/116169071/ref=sa_menu_kindle_l3_116169071#",1:5)
试着抓取第一个URL,也就是排名在1~20的图书….
## 我不是机器人,Amazon别封我IP~Sys.sleep(runif(1,1,2))doc<-htmlParse(URL[1],encoding="UTF-8")rootNode<-xmlRoot(doc)
可以看到已经过把网页内的信息抓下了,不过书籍的信息不是类似表格的形式,(如果是表格,应该具有类似<table>
的标签,可以直接用readHTMLTable
来读取) 在这里我使用xpathSApply
来读取标签内的信息:
先看下一个书籍的html源码:
<div class="zg_itemRow">
<div class="zg_item_compact">
<div class="zg_image zg_itemLeftDiv_compact">
<div class="zg_itemImage_compact">
<a href="http://www.amazon.cn/%E8%A7%A3%E5%BF%A7%E6%9D%82%E8%B4%A7%E5%BA%97-%E4%B8%9C%E9%87%8E%E5%9C%AD%E5%90%BE/dp/B00NOQNHP2/ref=zg_bs_116169071_1
">
<img src="http://ec4.images-amazon.com/images/I/51F6FK4cLGL._SL160_SL135_.jpg" alt="解忧杂货店" title="解忧杂货店" onload="if (typeof uet == 'function') { uet('af'); }"/></a>
</div>
</div>
<div class="zg_itemRightDiv_compact">
<div class="zg_rankLine">
<span class="zg_rankNumber">1.</span>
<span class="zg_rankMeta"></span>
</div>
<div class="zg_title">
<a href="http://www.amazon.cn/%E8%A7%A3%E5%BF%A7%E6%9D%82%E8%B4%A7%E5%BA%97-%E4%B8%9C%E9%87%8E%E5%9C%AD%E5%90%BE/dp/B00NOQNHP2/ref=zg_bs_116169071_1">解忧杂货店</a>
</div>
<div class="zg_byline">~ 东野圭吾 (作者), 李盈春 (译者)</div>
<div class="zg_reviews">
(<a href="http://www.amazon.cn/product-reviews/B00NOQNHP2/ref=zg_bs_116169071_cm_cr_acr_txt?ie=UTF8&showViewpoints=1" >3,360</a>)</span...
看起来很乱是不是,我们主要需要从这里面找到我们需要的数据,并用一个Xpath来解读它,什么,不懂Xpath?其实没多大关系,给一个最简单的Xpath,然后照着修改就好:
给我个价格
比如我们想要里面的价格数据,先找到对应的标签:
<strong class="price">¥ 5.93</strong>
strong是代表该部分粗体,class是price,这个DOM标签对应的是"//strong[@class='price']"
意思就是寻找strong的类,strong的class是price,在R里面获取下Price的数据:
givePrice = function(rootNode){
price<-xpathSApply(rootNode,"//strong[@class='price']",xmlValue)
price
## 收费付费混排,我只要付费的价格(循环补齐式选择)
(price = price[c(T,F)])
## 喂,你给我认真处理下数据,把¥去掉,再转数字
strsplit(price," ") -> price.c
unlist(price.c)[c(F,T)] -> price.c
as.numeric(price.c)[1:20] -> price
price}givePrice(rootNode)
## [1] 12.00 0.79 9.99 2.99 0.99 2.99 2.00 2.00 0.10 3.99 16.99
## [12] 18.00 1.99 8.99 0.99 0.99 3.99 2.00 1.99 1.99
给我个评价
要抓取的内容为:
<a style="text-decoration:none" href="http://www.amazon.cn/product-reviews/B00NOQNHP2/ref=zg_bs_116169071_cm_cr_acr_img?ie=UTF8&showViewpoints=1" name="reviewHistoPop_B00NOQNHP2_5288_star__" ><span class="swSprite s_star_4_5 " title="平均4.7 星" ><span>平均4.7 星</span></span> </a>
Xpath为:"//a[@style='text-decoration:none']/span"
giveRate = function(rootNode){
rate<-xpathSApply(rootNode,"//a[@style='text-decoration:none']/span",xmlValue)
rate[c(T,F,F,F)] -> rate
strsplit(rate,"平均") -> rate.c
unlist(rate.c)[c(F,T)] -> rate.c
strsplit(rate.c," 星") -> rate.c
unlist(rate.c) -> rate.c
as.numeric(rate.c) -> rate
rate}giveRate(rootNode)
## [1] 4.2 4.4 4.3 4.4 4.3 4.5 4.4 4.3 4.5 4.2 4.5 4.2 4.6 4.6 4.4 4.6 4.4
## [18] 4.6 4.7 4.5
为什么要认真处理数据呢,因为评价在后期说不定需要进行比较并找到最高评分的书籍,所以在前期要做好数据的清理.
给我评价数
我在刷Amazon的时候,发现有书竟然能到5.0的评分(竟然是满分!)细看一下只有4个评分.所以获得评价数量应当也是其中的一环(哪怕最终用不到这个数据)
Xpath为:"//a[@style='text-decoration:none']/span"
giveNumber = function(rootNode){
number<-xpathSApply(rootNode,"//span[@class='crAvgStars']/a",xmlValue)
number[c(T,F)] -> number.c
sub(",","",number.c) ->number.c
as.numeric(number.c)}giveNumber(rootNode)
## [1] 79 466 2137 706 540 533 141 1734 528 184 63 406 256 380
## [15] 326 547 257 464 218 311
给我书名
刷出书名:
giveNames = function(rootNode){
names <- xpathSApply(rootNode,"//div[@class='zg_title']/a",xmlValue)
names[c(T,F)]}giveNames(rootNode)
## [1] "斯坦福极简经济学"
## [2] "话语操纵术2:不可思议的催眠式说服技巧 (话语操纵术系列)"
## [3] "解忧杂货店"
## [4] "最璀璨的银河——刘慈欣经典作品集"
## [5] "春日便当"
## [6] "你一定爱读的极简欧洲史(简约不简单的“最短”欧洲史,任志强、钱理群、钱文忠、公孙策联合推荐!)"
## [7] "狼图腾 (九头鸟长篇小说文库)"
## [8] "乖,摸摸头"
## [9] "浮生六记"
## [10] "张鸣说历史:重说中国国民性"
## [11] "血腥的盛唐大全集(珍藏版)(套装全7册)"
## [12] "从0到1:开启商业与未来的秘密(图文精编版) (奇点系列)"
## [13] "经典短篇小说101篇(英文原版) (西方经典英文读物) (English Edition)"
## [14] "白夜行"
## [15] "何以笙箫默"
## [16] "理想实习生"
## [17] "第一夜"
## [18] "从你的全世界路过"
## [19] "人生的智慧 (叔本华系列)"
## [20] "从零开始学炒股:新手入门、大智慧详解、买卖之道"
给我作者
再刷出作者:
giveAuthors = function(rootNode){
authors <- xpathSApply(rootNode,"//div[@class='zg_byline']",xmlValue)
authors[c(T,F)] -> authors
sub("nnnnnnn~ ","",authors)}giveAuthors(rootNode)
## [1] "(美)泰勒 (作者), 林隆全 (译者)"
## [2] "大卫•拜伦 (作者), 刘祥亚 (译者)"
## [3] "东野圭吾 (作者), 李盈春 (译者)"
## [4] "刘慈欣 (作者)"
## [5] "〔日〕吉井忍 (作者)"
## [6] "约翰•赫斯特 (作者), 席玉苹 (译者)"
## [7] "姜戎 (作者)"
## [8] "大冰 (作者)"
## [9] "(清)沈复著;朱奇志 校译 (作者)"
## [10] "张鸣 (作者)"
## [11] "王觉仁 (作者)"
## [12] "彼得·蒂尔 (作者), 布莱克·马斯特斯 (作者), 高玉芳 (译者)"
## [13] "(美)欧•亨利等 (作者)"
## [14] "东野圭吾 (Higashino Keigo) (作者), 刘姿君 (译者)"
## [15] "顾漫 (作者)"
## [16] "肖桐 (作者)"
## [17] "M.) (法) 李维 (Levy (作者), 李月敏 (译者)"
## [18] "张嘉佳 (作者)"
## [19] "叔本华(Arthur Schopenhauer) (作者), 韦启昌 (译者)"
## [20] "杨金 (作者)"
祭出主程序
我们之前刷出来了这几个函数:
givePrice
- 求价格
giveRate
- 求评价
giveNumber
- 求评价数
giveNames
- 求书名
giveAuthors
- 求作者
组合到一起,合成获取某一个URL的主函数:
getAmazonBy1 = function(URL){
Sys.sleep(runif(1,1,2))
doc<-htmlParse(URL[1],encoding="UTF-8")
rootNode<-xmlRoot(doc)
data.frame(
Price = givePrice(rootNode), # 求价格
Rate = giveRate(rootNode), # 求评价
Number = giveNumber(rootNode), # 求评价数
Name = giveNames(rootNode), # 求书名
Author = giveAuthors(rootNode)
# 求作者
)}
不过要注意的是,在win下刷出来的是UTF-8码,噗哈哈,我去用linux跑该脚本啦~
最后一步
多个网址,刷出各个排名并组合到一起:
URL = paste0("http://www.amazon.cn/gp/bestsellers/digital-text/116169071/ref=sa_menu_kindle_l3_116169071#",1:5)mainfunction = function(URL){
data = rbind(
getAmazonBy1(URL[1]), getAmazonBy1(URL[2]), getAmazonBy1(URL[3]), getAmazonBy1(URL[4]), getAmazonBy1(URL[5]))
data = cbind(data,1:100) }mainfunction(URL)
保存好今天的数据,明天再来一次,就可以看看每天上升最快的本书了,然后呢,买来看啊….amazon数据是每小时更新的,我做此文的时候也刷了一次数据.
获取日上升最快的书籍
library(dplyr)
##
## Attaching package: 'dplyr'
##
## The following object is masked from 'package:stats':
##
## filter
##
## The following objects are masked from 'package:base':
##
## intersect, setdiff, setequal, union
getImprove = function(t=0){today = read.csv(paste0(Sys.Date()-t,".csv"))yesterday = read.csv(paste0(Sys.Date()-1-t,".csv")) yesterday = select(yesterday,Name,yes = X1.100)final = left_join(today, yesterday, by = "Name") %>%
mutate(.,yes = ifelse(is.na(yes),100,yes)) %>%
mutate(.,improve = yes-X1.100) %>%
arrange(.,desc(improve))head(final)}getImprove(t = 20)
## Name X Price Rate Number
## 1 世界上的另一个你 (最佳译文:53) 37 1.99 4.6 5
## 2 哈默手稿 29 3.99 4.3 170
## 3 说不尽的外交 51 6.99 4.5 114
## 4 神似祖先 (视点文丛) 45 3.99 4.5 55
## 5 孤独的人都要吃饱 49 2.99 4.2 17
## 6 潮汕味道 (潮汕文化丛书•岭南文化书系) 59 4.99 4.5 28
## Author
## 1 R.) , ( 美) 摩尔 (Moore,D.) ( 美) 霍尔 (Hall (作者), 李佳纯 (译者)
## 2 列奥纳多•达•芬奇 (Leonardo da Vinci) (作者), 李秦川 (译者)
## 3 李肇星 (作者)
## 4 郑也夫 (作者)
## 5 张佳玮 (作者)
## 6 张新民 (作者)
## X1.100 yes improve
## 1 37 100 63
## 2 29 78 49
## 3 51 100 49
## 4 45 89 44
## 5 49 93 44
## 6 59 100 41
最后程序:
library(XML)givePrice = function(rootNode){
price<-xpathSApply(rootNode,"//strong[@class='price']",xmlValue)
price
## 收费付费混排,我只要付费的价格(循环补齐式选择)
(price = price[c(T,F)])
## 喂,你给我认真处理下数据,把¥去掉,再转数字
strsplit(price," ") -> price.c
unlist(price.c)[c(F,T)] -> price.c
as.numeric(price.c)[1:20] -> price
price}giveRate = function(rootNode){
rate<-xpathSApply(rootNode,"//a[@style='text-decoration:none']/span",xmlValue)
rate[c(T,F,F,F)] -> rate
strsplit(rate,"平均") -> rate.c
unlist(rate.c)[c(F,T)] -> rate.c
strsplit(rate.c," 星") -> rate.c
unlist(rate.c) -> rate.c
as.numeric(rate.c) -> rate
rate}giveNumber = function(rootNode){
number<-xpathSApply(rootNode,"//span[@class='crAvgStars']/a",xmlValue)
number[c(T,F)] -> number.c
sub(",","",number.c) ->number.c
as.numeric(number.c)}giveNames = function(rootNode){
names <- xpathSApply(rootNode,"//div[@class='zg_title']/a",xmlValue)
names[c(T,F)]}giveAuthors = function(rootNode){
authors <- xpathSApply(rootNode,"//div[@class='zg_byline']",xmlValue)
authors[c(T,F)] -> authors
sub("nnnnnnn~ ","",authors)}getAmazonBy1 = function(URL){
Sys.sleep(runif(1,1,2))
doc<-htmlParse(URL[1],encoding="UTF-8")
rootNode<-xmlRoot(doc)
data.frame(
Price = givePrice(rootNode), # 求价格
Rate = giveRate(rootNode), # 求评价
Number = giveNumber(rootNode), # 求评价数
Name = giveNames(rootNode), # 求书名
Author = giveAuthors(rootNode)
# 求作者
)}#################主程序部分############################3mainfunction = function(URL){
data = rbind(
getAmazonBy1(URL[1]), getAmazonBy1(URL[2]), getAmazonBy1(URL[3]), getAmazonBy1(URL[4]), getAmazonBy1(URL[5]))
data = cbind(data,1:100) }################运行部分###############################3URL = paste0("http://www.amazon.cn/gp/bestsellers/digital-text/116169071/ref=zg_bs_116169071_pg_1?ie=UTF8&pg=",1:5)data = mainfunction(URL) write.csv(data, file = paste0(Sys.Date(),".csv"))
- HLS Lesson16-数组优化:数组分割
- HLS Lesson15-for循环优化:其他方法
- 对自己的上网搜索记录进行爬虫是怎样一种体验
- HLS Lesson13-for循环优化:合并
- HLS Lesson12-for循环优化:基本性能指标
- HLS Lesson11-c/c++ testbench书写续2
- 【机器学习】实例详解机器学习如何解决问题
- 企业网站架构之Nginx+tomcat+memcached集群
- 企业级Docker Registry开源工具Harbor的介绍以及使用指南
- HLS Lesson8-基本操作
- Windows渗透测试工具:RedSnarf
- HLS Lesson7-复合数据类型
- matlab GUI基础3
- 【Python环境】《Python数据科学入门》试译 第一章 简介
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 在 Python 中如何快速创建一个只读字典?
- 现场打脸:如何使用Selenium批量上传文件?
- 一日一技:FastAPI如何关闭接口文档?
- 什么叫做类比,为什么有些 Python 入门教程结构不合理?
- 贼好用的 Java 工具类库,墙裂推荐!
- 万字长文,Thread 类源码解析!
- lintCode 31 题解
- JDK1.8HashMap源码学习-put操作以及扩容(二)
- Python 中的数字到底是什么?
- 详解 Python 的二元算术运算,为什么说减法只是语法糖?
- 详解增强算术赋值:“-=”操作是怎么实现的?
- Hyperledger Explorer 环境搭建详解
- [译]在Solidity中创建无限制列表
- java安全编码指南之:声明和初始化
- java安全编码指南之:表达式规则