爬虫连载系列(3)--爬取京东商城
飞小飞 人气:0
## 前言
这两天原本想在淘宝上爬点东西进行分析的,但没想到淘宝的反爬机制对我这个爬虫菜鸡充满了恶意。先是被数据的格式搞得焦头烂额,好不容易写好了测试一页的代码,准备美滋滋开始大显身手,爬取多页时,发现竟然被封IP了!呜呜┭┮﹏┭┮。于是,开始研究各种反反爬的机制,IP代理,多线程、模拟登陆... ...发现自己的盲区越来越大。眼瞅着与自己的博客更新计划越行越远,只好先换个目标,对某东下手。但并不代表我会放过它,等自己在修炼一段时间,再来会会它。下面,我们开始进入正题吧。
这次想做一个关于**糖果**的分析,于是爬取了京东共2700左右条的数据,这个数据应该是够自己分析了。京东比较坑的一点是,他的每一页是先加载一部分,另一部分是通过动态加载的。为此,我的解决办法是,使用Selenium构建模拟浏览器,先通过执行脚本,下滑到底部,等全部数据加载完成后,在进行读取。哦,对了,这次使用的解析库是xpath。
### 要点
用到的库:selenium、urllib、pandas、csv、lxml
工具: python 3.7、jupyter notebook
## 分析
### 网页分析
首先,我们进入京东商城,搜索框中输入**糖果**,进入开发者模式。
![\[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ySX78DDF-1584365178843)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20200316202344764.png)\]](https://img-blog.csdnimg.cn/2020031621271260.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L01pcmFjbGVfSDEy,size_16,color_FFFFFF,t_70)
发现这也太简单了叭,按捺不住内心的鸡冻,马上就想要开始写代码。
慢着
![img](https://imgconvert.csdnimg.cn/aHR0cHM6Ly9kc3MwLmJkc3RhdGljLmNvbS83MGNGdUhTaF9RMVlueEdrcG9XSzFIRjZoaHkvaXQvdT0xNTc3MzE2MDc0LDI4MTE0ODk5ODQmZm09MTUmZ3A9MC5qcGc?x-oss-process=image/format,png)
我们先看看Network的输出,
![\[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nZSpnium-1584365178851)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20200316203358532.png)\]](https://img-blog.csdnimg.cn/20200316212747105.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L01pcmFjbGVfSDEy,size_16,color_FFFFFF,t_70)
细细看一下Preview中的商品,如果你点一下,你会发现只有30个商品,而页面中共有60个商品,你会发现事情并不简单。
下滑到底部后,你在刷新下Network输出,你会发现,这里多了个这个js文件
![\[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OIU06gjc-1584365178852)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20200316203704329.png)\]](https://img-blog.csdnimg.cn/2020031621301732.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L01pcmFjbGVfSDEy,size_16,color_FFFFFF,t_70)
而这里就是剩下的30条数据。
哦,我懂了,不就是先加载30条数据,后30条数据在你滑动浏览的过程中加载嘛。
![img](https://imgconvert.csdnimg.cn/aHR0cHM6Ly9kc3MxLmJkc3RhdGljLmNvbS83MGNGdVhTaF9RMVlueEdrcG9XSzFIRjZoaHkvaXQvdT0zNjMwNDA3Nzc3LDMwNTQ0MjY2NzAmZm09MjYmZ3A9MC5qcGc?x-oss-process=image/format,png)
这时候,我们前面介绍的主角就登场了:Selenium 。通过它,构建一个虚拟浏览器,先执行一个脚本,下滑到最底部,加载完数据后我们在进行爬取。
**注意:**使用他,你要先安装谷歌插件(谷歌浏览器的话),还得添加驱动。具体操作步骤,请移步百度。
### url分析
分析完网页结构后,我们来分析下url的构成
前30条数据的
https://search.jd.com/Search?keyword=%E7%B3%96%E6%9E%9C&enc=utf-8&qrst=1&rt=1&stop=1&vt=2&page=1&s=1&click=0
后30条数据的
https://search.jd.com/s_new.php?keyword=%E7%B3%96%E6%9E%9C&enc=utf-8&qrst=1&rt=1&stop=1&vt=2&wq=%E7%B3%96%E6%9E%9C&page=2&s=31&scrolling=y&log_id=1584362139.53979&tpl=1_M&show_items=100007265728,4695858,1227178,4838836,326467,100000424178,100000217809,1083784,4005567,1153605,1153613,4707850,1153610,1178879,4476739,794422,100008420904,100000757536,6338667,100004891346,4476767,30494640062,4491861,3816695,523631,4476753,2210373,679518,3692931,903403
发现两个中,前面构成是基本一致的,
keyword:搜索关键字
log_id:是后30个商品的商品id
经过实验,我们发现简化后可用的url:https://search.jd.com/Search?keyword=%E7%B3%96%E6%9E%9C&enc=utf-8&qrst=1&rt=1&stop=1&vt=2&page=1&s=1&click=0
在看下第二页:
https://search.jd.com/Search?keyword=%E7%B3%96%E6%9E%9C&enc=utf-8&qrst=1&rt=1&stop=1&vt=2&page=3&s=61&click=0
第三页 (此处省略100字) ... ...
得出url的规律: page = 2*页数 - 1
分析完这些后,就可以进行快乐的编码模式了
## 代码
直接上代码吧
```
import time
from selenium import webdriver
from lxml import etree
import urllib
import csv
import pandas as pd
import random
#获取页面
def get_page(depth):
keyword = "糖果"
headers = {
"User-Agent":"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/537.36"
}
base_url = 'https://search.jd.com/Search?keyword={}&enc=utf-8&qrst=1&rt=1&stop=1&vt=2&stock=1&page={}'
for page_num in range(1,depth):
try:
start_url = base_url.format(urllib.parse.quote(keyword),page_num*2-1)
driver = webdriver.Chrome()
driver.get(start_url)
driver.execute_script("window.scrollTo(0,document.body.scrollHeight);") #执行下滑到底部的操作
time.sleep(10) #必须休眠,等待获取完全部信息
#获取页面信息
source = driver.page_source # 等同于 response = requests.get(url = start_url,headers=headers)
html = etree.HTML(source)
item = parse_page(html)
write_excel(item)
print('爬取第'+str(page_num)+'页时成功!')
time.sleep(random.randint(2,6))
except:
print('爬取第'+str(page_num)+'页时出错!')
continue
#解析页面
def parse_page(html):
li = html.xpath('//*[@id="J_goodsList"]/ul/li')
for one_li in li:
yield{
'price':one_li.xpath('divhttps://img.qb5200.com/download-x/div[2]/strong/i/text()')[0],
'title':get_title(one_li),
'comment_num':one_li.xpath('divhttps://img.qb5200.com/download-x/div[4]/strong/a/text()')[0],
'shop' :get_shop(one_li),
'goods_url':'http://'+one_li.xpath('divhttps://img.qb5200.com/download-x/div[1]/a/@href')[0]
}
# #获取标题
def get_title(item):
title_list = item.xpath('divhttps://img.qb5200.com/download-x/div[3]/a/em/text()')
title = ' '.join(title_list)
return title
#获取店铺名称
def get_shop(item):
shop=item.xpath('divhttps://img.qb5200.com/download-x/div[5]/span/a/text()')
if len(shop) == 0:
return '未知'
else:
return shop[0]
#写入csv文件中
def write_excel(item):
good_df = pd.DataFrame(item)
good_df.to_csv('./JongDong.csv',mode='a',encoding= 'utf-8-sig')
def main():
get_page(50)
if __name__ == "__main__":
main()
```
运行结果:
![\[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1A2JDVeQ-1584365178862)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20200316210020249.png)\]](https://img-blog.csdnimg.cn/2020031621305184.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L01pcmFjbGVfSDEy,size_16,color_FFFFFF,t_70)
![\[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9zvOfeAK-1584365178865)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20200316210255995.png)\]](https://img-blog.csdnimg.cn/20200316213112766.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L01pcmFjbGVfSDEy,size_16,color_FFFFFF,t_70)
![\[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sgj7bs6j-1584365178869)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20200316210637929.png)\]](https://img-blog.csdnimg.cn/202003162131359.png)
嗯,很好,都爬取成功了
![img](https://imgconvert.csdnimg.cn/aHR0cHM6Ly9kc3MxLmJkc3RhdGljLmNvbS83MGNGdVhTaF9RMVlueEdrcG9XSzFIRjZoaHkvaXQvdT0yMjE3NDYyOTg1LDg2NjY4NTg1MCZmbT0yNiZncD0wLmpwZw?x-oss-process=image/format,png)
真的嘛?你不是说一页60,60*49 = 2940.你别欺负我读书少!!!
好吧,我承认是漏了些数据。但我发4,这绝对不是我代码的问题,我测试过爬取单页和爬前几页时是能够爬取完整的。真的只是我家网的问题,没来得及加载完全部数据。虽然我也设置了延时(休眠10s来获取数据),但可能这些时间里刚好碰上网卡情况。下午爬取时候,确实有段时间网特慢。下次,考虑加入retry,让它没爬取完整就重新爬,直到一页的数据爬取完整,变成一个真正合格的爬虫,同时,加入多线程,减少爬取的时间。再说,两千多条也足够用了,不是嘛。嘻嘻(●'◡'●)
## 后记
后面将用今天获得的数据进行分析,解锁**糖果**的密码。(●'◡'●)
加载全部内容