在此说明,这个项目是我第一次真正去爬的一个网站,里面写的代码我自己都看不下去,但是已经不想花时间去重构了,所以看个乐呵就好,要喷也可以(下手轻一点)。这篇文算是记录我的学习中出现的一些问题,不建议拿来学习和真拿我的代码去爬Lazada的数据,当然看看我的思路还是可以的。
我的目标是拿到个分类下的商品数据
1.获取各个分类的链接
2.获取各个分类下的商品链接
3.通过商品链接获取到需要的商品数据
import time
import openpyxl
import requests
import re
from lxml import etree
from selenium.webdriver.common.by import By
import bag # 这个包是别人写好给我的,我会在下面把用到的方法放出来
这个bag包里面的很多参数是不起作用的,可以不用管它。这里给Chrome浏览器设置了一个9222端口方便用程序控制自己打开的浏览器
class Bag:
def web_debug():
chrome_options = Options()
chrome_options.add_experimental_option('debuggerAddress', '127.0.0.1:9222')
chrome_options.page_load_strategy = 'eager'
chrome_options.add_argument('–disable-gpu') # 谷歌文档提到需要加上这个属性来规避bug
chrome_options.add_argument('--incognito')
chrome_options.add_argument('--disable-javascript')
chrome_options.add_argument('--enable-automation')
chrome_options.add_argument('--no-sandbox') # 解决DevToolsActivePort文件不存在的报错
chrome_options.add_argument('blink-settings=imagesEnabled=false') # 不加载图片, 提升速度
web = Chrome(service=Service(), options=chrome_options)
return web
右键Chrome浏览器的属性把目前路径改成如下:
C:\Program Files\Google\Chrome\Application\chrome.exe (括号里面的是解释用的时候记得删掉:前面是你谷歌浏览器的放在文件夹里的位置)[--headless] --remote-debugging-port=9222 --user-data-dir="D:\工作文件\data (还要创建一个放数据的文件夹)
设置好后就可以win+R打开运行窗口,输入cmd打开Windows命令行窗口:
输入如下命令:
cd C:\Program Files\Google\Chrome\Application\ (浏览器在电脑中的位置)
chrome.exe --remote-debugging-port=9222 --user-data-dir="D:\工作文件\data"
就可以打开一个浏览器,到时候我们让程序通过端口控制自己打开的浏览器,这样好突破网站的反爬手段
讲了那么多终于开始准备爬虫了(再次吐槽自己写的是什么鬼东西搞这么复杂),下面是进行第一步拿到分类的链接。
通过下一页还有F12的一个观察,发现链接数据都是通过访问如下链接请求回来的
这是第一个分类第三页的链接:https://www.lazada.sg/shop-power-banks/?ajax=true&isFirstRequest=true&page=3&spm=a2o42.searchlistcategory.cate_1_1.2.46115305qPLfPu
然后?之后的链接都是可以不用要的,但是为了页数我们只把page= 后面的链接删了,page是控制页数的参数
整理如下
https://www.lazada.sg/shop-power-banks/?ajax=true&isFirstRequest=true&page=3
再观察发现链接中的这部分
刚好就是最小的那个分类的名字,那这个链接就好搞了
通过xpath定位可以找到分类的链接
爬取分类链接的代码如下:
头文件和cookie,要设置好,不然网站不会返回数据
headers = {
'User-Agent': ''
}
cookies = {
'cookie': ''
}
def shop_spider(url):
'''
遇到的问题:
1.在获取商品分类界面的url时request访问回来的数据不全(网页源代码有数据)。 解决方法:这个网站需要添加cookie
2.形成的JSON链接有一些是错误的,使用时需要抛出异常
3.只爬取了分类下的第一页的链接
'''
# 获取商品分类界面url
req = requests.session().get(url, headers=headers, cookies=cookies).text
ht = etree.HTML(req)
li = ht.xpath("//li[@class='lzd-site-menu-grand-item']/a/@href") # 分类界面
# 组合获取到的分类名字,形成分类链接
url_list = []
for i in li:
url_list.append('https:' + i + '?ajax=true&isFirstRequest=true&page=1')
# 将获取到的链接存入到txt文档中
f = open('D:\\工作文件\\lazadaurl.txt', 'w', encoding='utf8')
f.write('\n'.join(url_list))
f.close()
shop_spider('https://www.lazada.sg/') # 启动函数
很好,现在我们完成了第一步,现在到第二步:从获取到的分类界面链接里面提取出商品的链接
实现代码:
def lazada_json():
f = open('D:/工作文件/lazadaurl.txt') # 这里放的是前面爬到的分类链接
ls = []
for i in f:
try:
# 发起request请求session是保存之前cookie等数据,拿JSON格式的数据回来
req = requests.session().get(i, headers=headers, cookies=cookies).json()
# 正则匹配出需要的url
js = re.findall(ir, str(req))
# 集合(set)去重
li = list(set(js))
# 循环寻找可以访问的链接(找回来的数据是只有//www开头的链接才可以访问),是就写进一个新的列表,不是就pass
for j in li:
if j[:5] == "//www":
ls.append(j)
else:
pass
except Exception as arr:
print(arr) # 抛出异常名字和出现异常的链接
continue # 抛出异常继续爬取
# 保存爬取到的链接,以待后面爬商品的详情数据
url = []
for i in ls:
url.append('https:' + i) # 组合成商品详情页链接
f = open('D:\\工作文件\\url.txt', 'w')
f.write(str('\n'.join(url)))
f.close()
接下来到我们的第三步,爬商品详情页的数据了。这也是本人最不满意的一部分,也是问题最多的一部分。
拿数据的部分如下图,当然还有商品的链接:
爬取代码如下:
def lazada_data():
f = open('D:/工作文件/没爬的url1.txt', encoding='utf8')
p = open(r'D:\工作文件\没爬的url.txt', 'a')
url = []
for r in f:
url.append(r)
l = openpyxl.load_workbook('D:/工作文件/text.xlsx') # 读取已经有的工作簿
sheet1 = l['sheet1'] # 创建sheet工
ch = bag.Bag.web_debug() # 使用bag包里面的方法创建浏览器
x = 1 # 这是写入到Excel里面的第几行,也表示着现在爬到了第几条链接
for i in url[0:]: # 这里可以选择从第几条开始爬,记得要-1,因为列表是从0开始数
data = []
bq1 = []
ch.get(i)
# 出现验证码拦截界面时停止程序,手动处理验证码之后再从新启动
if ch.title == '验证码拦截':
print('在第' + str(x) + '终止')
l.save('D:/工作文件/text.xlsx') # 保存.xls到当前工作目录
exit(0)
# 处理当商品已经下架之后的状况
if ch.title == 'non-existent products':
continue
try:
ch.implicitly_wait(100)
time.sleep(1)
data.append(ch.find_element(By.XPATH, '//*[@id="module_product_title_1"]/div/div/h1').text) # 标题
data.append(ch.find_element(By.XPATH, '//*[@id="module_product_brand_1"]/div/a[1]').text) # 品牌
bq = ch.find_elements(By.XPATH, '//*[@id="J_breadcrumb"]/li/span/a') # 分类标签
for k in bq:
bq1.append(k.get_attribute('text'))
data.append(bq1)
data.append(ch.find_element(By.XPATH, '//*[@id="module_product_review_star_1"]/div/a').text) # 评级
req = requests.session().get(i, headers=headerss, cookies=cookiess).text
et = etree.HTML(req)
jj = re.findall(jre, str(req))
# 判断有没有拿到简介的数据,没有就跳过,加入到后续补爬的文件里面
if jj:
data.append(jj) # 简介
else:
print('第' + str(x) + '条链接的简介没拿到!')
p.write(i)
continue
data.append(et.xpath("//img[@class='pdp-mod-common-image item-gallery__thumbnail-image']/@src")) # 商品图片链接
data.append(i) # 商品详情页链接
# 保存到xlsx文件里,因为这里列表里面套列表([1,2,[4,5,6],3]),所以加个判断(当然这部分还可以优化,懒了,不想改了)
for y in range(len(data)):
if type(data[y]) != list:
sheet1.cell(x, y + 1).value = data[y] # 写入数据参数对应 行, 列, 值
else:
sheet1.cell(x, y + 1).value = '\n'.join(data[y])
x += 1
except Exception as arr:
print('第' + str(x) + '条错误,已经加入未爬取文件')
p.write(i)
continue
if x % 500 == 0:
l.save(r'D:/工作文件/text.xlsx') # 保存.xls到当前工作目录
l.save('D:/工作文件/text.xlsx') # 保存.xls到当前工作目录
p.close()
main函数启动,一个个起就可以了
if __name__ == '__main__':
# shop_spider('https://www.lazada.sg/')
# lazada_json()
lazada_data()
商品详情的数据爬取这部分在分类标签这部分用了拦截器函数,具体的原理我还没研究明白
小小的总结一下吧,在获取链接的那两部分我个人感觉还OK,就是在数据获取那边用的方法非常的混乱,用了selenium自动化爬虫,接下又对同一个链接发request请求,说实话真的有点多余了,但是我有不知道怎么把拿商品的介绍这部分,所以才使用了这样的一个非常臃肿的方法(不要学)。
具体的结果图我就不放出来了,本来就是记录一下自己的学习过程的。