我们来了解一下京东的商品爬取。
爬取方式是selenium+chromedriver获取数据。
我们首先分析一下京东网站,比较神奇
一:构造链接
我们以手机为例
我们观察一下第二页和第三页可以发现,改变的参数是page和s,倒数第二和第三项,从page看,似乎只有奇数页,也就是1,3,5。
那么,s是什么?为什么page不是1,2,3递增而是1,3,5?其他参数会影响别的商品爬取吗?比如,我还要爬钱包,是不是报keyword改成钱包的编码就行了?如果行就好,如果不行怎么办?参数从哪拿?上面全部都是必要参数吗?
一一解答:s参数未知,但它是无用参数,page1,3,5递增是因为,加载出每一页的数据,后半部分是ajax请求的数据,该部分其实也是单独页,也就是偶数页。其他参数影响爬取其他商品,因此不可行。部分参数非必要,看看请求,我们就可以拿到必要参数。
我们可以看见它发送了一个ajax的请求,page是2,也就是说,偶数页在奇数页下面,通过ajax获取。
其实,url的构造,只需要:
'https://search.jd.com/Search?keyword={}&enc=utf-8&qrst=1&rt=1&stop=1&vt=2&page={}&click=0'
在第一ge{}传商品名,第二个{}传页数。
二:ajax数据获取:
ajax数据隐藏在原数据下面,而且参数也不完全相同,直接把参数的page改成偶数,也不一定可行(我没试过),所以这里使用了selenium+chromedriver的方法,下拉界面,加载出ajax数据,在获取page_source即可。
我们上一下代码:
from selenium import webdriver
from lxml import etree
import time
import pymysql
from pymongo import MongoClient
class JDspider():
def __init__(self):
self.driver_path = 'D:\pythontools\chromedriver.exe'
self.driver = webdriver.Chrome(executable_path=self.driver_path)
self.base_url = 'https://search.jd.com/Search?keyword={}&enc=utf-8&qrst=1' \
'&rt=1&stop=1&vt=2&page={}&click=0'
#链接MySQL数据库
self.db = pymysql.connect(host="localhost", user="root", password="123",
database="jd", port=3306)
# 获取游标
self.cursor = self.db.cursor()
#链接mongodb
self.client = MongoClient()
self.mdb = self.client['jd']
self.collection = self.mdb['jd_shop']
#构造url
#京东网页前半部分普通加载为奇数页,后半部分属于ajax加载为偶数页
#构造奇数页url,模拟浏览器下拉,获取偶数页数据,共获取2页
def stru_url(self):
category_list = ['手机','奢侈品','电脑','书籍','无人机','乐器','钟表','数码影音','生活电器']
for category in category_list:
#偶数页通过下拉浏览器界面获取数据,过滤掉偶数
for x in range(1,3):
if x%2 == 0:
continue
url = self.base_url.format(category,x)
self.get_list_url(url,category)
# print(url)
# break
# break
time.sleep(5)
time.sleep(5)
#获取商品详情链接的url
def get_list_url(self,url,category):
self.driver.get(url)
# js语句。将浏览器界面下拉5000个单位,加载出ajax请求数据
js = "var q=document.documentElement.scrollTop=5000"
self.driver.execute_script(js)
#等待数据载入
time.sleep(5)
resp = self.driver.page_source
html = etree.HTML(resp)
detail_urls = html.xpath('//ul[contains(@class,"gl-warp")]/li//div[@class="p-img"]/a/@href')
for detail_url in detail_urls:
if "https:" not in detail_url:
detail_url = "https:" + detail_url
else:
continue
print(detail_url)
self.parse_detail(detail_url,category)
time.sleep(3)
#解析传入的url并做信息提取,将信息传给存储函数
def parse_detail(self,url,category):
shop = {}
#获取分类
category = category
self.driver.get(url)
#获取数据并解析
resp = self.driver.page_source
html = etree.HTML(resp)
# print(category)
#获取名字
name = "".join(html.xpath("//div[@class='sku-name']//text()")).strip()
# print(name)
#获取简介
detail = "".join(html.xpath("//div[@id='p-ad']/@title")).strip()
# print(detail)
#获取价格
price = "".join(html.xpath("//span[@class='p-price']//text()")).strip()
# print(price)
#获取图片链接
p_url = "".join(html.xpath("//img[@id='spec-img']/@src"))
p_url = "https:" + p_url
# print(p_url)
shop['category'] = category
shop['name'] = name
shop['detail'] = detail
shop['price'] = price
shop['p_url'] = p_url
self.save_sql(shop)
self.save_mongo(shop)
#接收要存储的数据,存储到sql数据库
def save_sql(self,shop):
sql = """
insert into jd_shop(id,name,detail,category,p_url,user_id,price) value
(null,%s,%s,%s,%s,null,%s)
"""
name = shop['name']
detail = shop['detail']
category = shop['category']
p_url = shop['p_url']
price = shop['price']
try:
self.cursor.execute(sql,(name,detail,category,p_url,price))
self.db.commit()
print("sql存储成功")
except Exception as e:
print("Error:",e.args)
#接收数据存储到mongodb数据量
def save_mongo(self,shop):
if self.collection.insert(shop):
print("mongo存储成功")
if __name__ == '__main__':
jd = JDspider()
jd.stru_url()
js = "var q=document.documentElement.scrollTop=5000"
self.driver.execute_script(js)
直接从列表页获取不到图片链接,只能进到详情页。
这个5000是自己试出来的,可以加载出ajax数据
商品名不需要编码,到链接自己会完成编码
存储到两个数据库,MySQL和MongoDB,同学需要。
MySQL:
部分数据,而且同学用于做自己的网站,不需要很多数据,所以量不大。
MongoDB:
完。。。。
最后,xpath获取数据强烈推荐xpath-helper,很好用,很直观。
链接:https://pan.baidu.com/s/10PGixiEPPfZQoioMw5oZKA
提取码:kmyz