这篇文章主要介绍如何用selenium抓取淘宝指定种类的所有商品列表 通过读取商品列表利用requests抓取天猫店铺的所有评论信息保存到mongodb
开始写爬虫代码前,我们需要先思考下你需要得到哪些信息
在这里,我需要得到的是淘宝指定商品的信息,包括价格、店铺、销量、标题、卖家、地址,还有就是各商品的所有用户评价信息,抓取到这些信息后可以方便我们后续的数据分析
最后面有我的完整代码
首先打开淘宝,审查元素
然后检查网页源代码,看网页源代码里是否含有商品的信息,在这里ctrl+f搜索某商品的价格,这里发现商品价格信息之类的都在一个script标签里,说明淘宝的商品列表都是通过js渲染出来的
那么我们可以用正则提取网页的商品信息,也可以用selenium,这里为了方便,我就用selenium了
下面是抓取商品信息的代码,如果不懂的话这里有视频详细解析,代码也源自这位博主,感谢他,我只是稍作修改
#导入需要的库
import re
from pyquery import PyQuery as pq #解析库
from selenium import webdriver
from selenium.common.exceptions import TimeoutException
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
browser = webdriver.Chrome()
#等待变量
wait = WebDriverWait(browser,10)
#模拟搜索
def search():
try:
browser.get('https://www.taobao.com/')#打开淘宝首页
tb_input = wait.until(
EC.presence_of_element_located((By.CSS_SELECTOR, '#q'))
)#等待输入框加载完成
search_btn = wait.until(
EC.element_to_be_clickable((By.CSS_SELECTOR, '#J_TSearchForm > div.search-button > button'))
)#等待搜索按钮加载完成
tb_input.send_keys('口红')#输入框中传入你需要搜索的商品
search_btn.click()#点击搜索
total = wait.until(
EC.presence_of_element_located((By.CSS_SELECTOR, '#mainsrp-pager > div > div > div > div.total'))
)#加载完成,获取页数元素
get_products()
return total.text#获取元素中的文本
except TimeoutException:
return search()#若发生异常,重新调用自己
#获取商品信息
def get_products():
wait.until(
EC.presence_of_element_located((By.CSS_SELECTOR, '#mainsrp-itemlist .items .item'))
)#等待商品信息加载完成,商品信息的CSS选择器分析HTML源码得到
html = browser.page_source#得到页面HTML源码
doc = pq(html)#创建PyQuery对象
items = doc('#mainsrp-itemlist .items .item').items()#获取当前页所有商品信息的html源码
for item in items:
#这里为了后面获取商品的评论信息,需要知道商品id以及店铺id
product = {
# 'image':item.find('.pic .img').attr('src'),
'itemid':item.find('.shop .shopname').attr('data-nid'),
'sellerid':item.find('.shop .shopname').attr('data-userid'),
'url':item.find('.title .J_ClickStat').attr('href'),
'price':item.find('.price').text(),
'deal':item.find('.deal-cnt').text()[:-3],
'title':item.find('.title').text(),
'seller':item.find('.shop').text(),
'location':item.find('.location').text()
}
print(product)
#翻页函数
def next_page(page_number):
try:
page_input = wait.until(
EC.presence_of_element_located((By.CSS_SELECTOR, '#mainsrp-pager > div > div > div > div.form > input'))
)#等待翻页输入框加载完成
confirm_btn = wait.until(
EC.element_to_be_clickable((By.CSS_SELECTOR, '#mainsrp-pager > div > div > div > div.form > span.btn.J_Submit'))
)#等待确认按钮加载完成
page_input.clear()#清空翻页输入框
page_input.send_keys(page_number)#传入页数
confirm_btn.click()#确认点击翻页
wait.until(EC.text_to_be_present_in_element(
(By.CSS_SELECTOR, '#mainsrp-pager > div > div > div > ul > li.item.active > span'), str(page_number))
)#确认已翻到page_number页
get_products()
except TimeoutException:
next_page(page_number)#若发生异常,重新调用自己
def main():
total = search()#获取商品页数,字符串类型
total = int(re.compile('(\d+)').search(total).group(1))#利用正则表达式提取数字,并强制转换为int类型
for i in range(2, total+1):
next_page(i)
browser.close()
if __name__ == '__main__':
main()
View Code
接下来我们就是将数据保存到数据库了
首先保存到mongodb的函数代码如下
import pymongo
#创建数据库以及数据表
client = pymongo.MongoClient('localhost',27017)
dataname = client['tb_kouhon']
table = dataname['goods_info']
def save_to_mongoDB(product):
try:
if table.insert(product):
print('存储到MongoDB成功',product)
except Exception:
print('存储到MongoDB失败',product)
View Code
将该函数插入到get_products()中
运行一下,淘宝每页有48个商品,总共100页,除掉重复的数据,发现和我们得到4000多条数据基本一致
接下来在练习一下保存数据到mysql
首先打开mysql终端创建数据库及数据表
#创建数据库
mysql> create database tb;
Query OK, 1 row affected (0.00 sec)
创建数据表
mysql> use tb;
Database changed
mysql> create table tb_inf(
-> id smallint unsigned auto_increment primary key,
-> itemid varchar(30),
-> sellerid varchar(30),
-> url varchar(200),
-> price varchar(20),
-> deal varchar(20),
-> title varchar(200),
-> seller varchar(50),
-> location varchar(50)
-> );
Query OK, 0 rows affected (0.22 sec)
View Code
然后创建存储到mysql的函数,这里要特别注意一点,利用pymysql插入数据到mysql是字符字段要有双引号括起来,不然会报错,这个非常重要,血泪般的教训==
def save_to_mysql(product):
sql = '''INSERT INTO tb_info(itemid,sellerid,url,price,deal,title,seller,location) VALUES (%s,%s,"%s","%s",%s,"%s","%s","%s")'''
try:
cursor.execute(sql % (product['itemid'],product['sellerid'],product['url'],product['price'],product['deal'],product['title'],product['seller'],product['location']))
conn.commit()
except:
conn.rollback()
View Code
ok,接下来运行下,爬几分钟就ok了,和上次爬的相比少了几十条数据,不过无关紧要了
接下来我们就是开始抓取淘宝各商品的评论了
这里因为淘宝商品有反爬策略,频繁爬取需要登录,还要输入验证码
所以在这里只演示爬取天猫商品的评论
首先我们随便打开一个天猫商品的全部评论,打开network,翻几页评论
点开response,可以发现里面全是json数据,这个list_detail_rate.htm?里面就是就是我们需要的数据
接下来我们看一下他的request url
这里我试了下,url可以简写成
https://rate.tmall.com/list_detail_rate.htm?itemId=546724870335&sellerId=3170729146¤tPage=4
访问下试试,如我们所料,评论都在这
在看下简化后url的构成,可以分成三部分itemId,sellerId,currentPage分别表示商品id,店铺id,评论页数
接下来就简单了
首先我们把上面爬取到的商品信息读取出来
import pymongo
client = pymongo.MongoClient('localhost',27017)
dataname = client['tb_kouhon']
table = dataname['goods_info']
allgoods = []
for i in table.find({}):
goodsdic = {'itemid':i['itemid'],
'sellerid':i['sellerid']}
allgoods.append(goodsdic)
print(allgoods)
View Code
然后构造爬取函数,构造函数前先要弄清它的json数据是怎么镶套的,弄清楚就好写代码了
def crawl_rank(itemid,sellerid):
url = 'https://rate.tmall.com/list_detail_rate.htm?itemId={}&sellerId={}¤tPage={}'
maxpage = get_page(itemid,sellerid)
print(maxpage)
for page in range(1,maxpage+1):
try:
header = {'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.91 Safari/537.36'}
response = requests.get(url.format(itemid,sellerid,page),headers= header)
html = response.text
formaljson = html[15:]
jsondata = json.loads(formaljson)
items = jsondata['rateList']
for item in items:
goodsrate = {'date':item['rateDate'],
'sku':item['auctionSku'],
'usernick':item['displayUserNick'],
'content':item['rateContent']}
save_to_mongo(goodsrate)
except:
continue
View Code
然后是获取总页数的函数和存储到mongo数据库的函数,这里的总页数也可以在json中获取到
def save_to_mongo(goodsrate):
try:
if table2.insert(goodsrate):
print('存储到MongoDB成功',goodsrate)
except Exception:
print('存储到MongoDB失败',goodsrate)
def get_page(itemid,sellerid):
try:
url = 'https://rate.tmall.com/list_detail_rate.htm?itemId={}&sellerId={}¤tPage={}'
header = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.91 Safari/537.36'}
response = requests.get(url.format(itemid,sellerid,0), headers=header)
html = response.text
formaljson = html[15:]
jsondata = json.loads(formaljson)
return jsondata['paginator']['lastPage']
except:
return get_page(itemid,sellerid)
def main():
for i in range(len(allgoods)):
goods = allgoods[i]
print(goods)
crawl_rank(goods['itemid'],goods['sellerid'])
View Code
运行main()试试看
这里有我的完整代码:github
到这里我们就大公告成了,以后有时间在研究下淘宝店铺的评论抓取
如果你对我的代码有什么疑问或者改进的地方,可以在评论里指出,大家互相交流才能取得进步,谢谢大家^^