免责声明:仅供学习,提高技术,请勿商业或恶意攻击网站等其他使用,欢迎留言,评论,点赞,转发!
由于亚马逊的机器检测比较灵敏,只能用scrapy+selenium
来实现数据爬取了,虽然大部分的内容都能获取得到,比如静态的文字,可以直接获取了。如果想获取商品图片的高清大图,可能就没有那么容易了,一步一分析开始了
首先,得先找到高清图片的URL
在哪儿吧,这个还是相对好找一些的,下图:
你会发现,data-old-hires
属性不就是高清图片的URL
地址吗,有了地址,获取图片不是近在咫尺吗?心中一阵狂喜。。。然而,左侧有四张图片,你才找到了一张,赶紧看看其他图片的高清地址,
咦?怎么其他图片难道没有高清地址
你准备放弃了,对不对,网页没有给数据,就是神仙,也拿不到啊?
别急,让我带你飞!
当你用鼠标,轻轻的滑过左侧四张缩略图时,右侧的li发生了变化
没错,我怀疑这是一个JS
里面鼠标滑过的类似事件,那还等什么,有selenium
怕什么,写鼠标滑动的操作呗,刚开始我就是这么操作的,但是效率是低的不能再低了,为什么呢?因为li
出现是没有那么规律的,有时候是第四个开始,有时候又是第三个开始,那每一个不得搞try
,下面是我之前写的代码:
try:
self.browser.get(request.url)
# 点击左侧缩略图
# slider = self.browser.find_element_by_css_selector("#nc_1_n1z") # 找到滑动标签
# X轴移动
try:
four = WebDriverWait(self.browser, 5).until(
lambda x: x.find_element_by_xpath('//*[@id="altImages"]/ul/li[4]'))
ActionChains(self.browser).click_and_hold(on_element=four).perform()
for x in [0, 10, 20, 30, 40, 50, 50, 40, 30, 20, 10, 0]:
ActionChains(self.browser).move_by_offset(xoffset=x, yoffset=0).perform()
ActionChains(self.browser).release().perform()
except Exception as e:
print(e)
try:
four = WebDriverWait(self.browser, 5).until(
lambda x: x.find_element_by_xpath('//*[@id="altImages"]/ul/li[1]'))
ActionChains(self.browser).click_and_hold(on_element=four).perform()
for x in [0, 10, 20, 30, 40, 50, 50, 40, 30, 20, 10, 0]:
ActionChains(self.browser).move_by_offset(xoffset=x, yoffset=0).perform()
ActionChains(self.browser).release().perform()
except Exception as e:
print(e)
# Y轴移动
try:
three = WebDriverWait(self.browser, 5).until(
lambda y: y.find_element_by_xpath('//*[@id="altImages"]/ul/li[3]'))
ActionChains(self.browser).click_and_hold(on_element=three).perform()
for y in [0, 10, 20, 30, 40, 50, 50, 50, 40, 30, 20, 10, 0]:
ActionChains(self.browser).move_by_offset(xoffset=0, yoffset=y).perform()
ActionChains(self.browser).release().perform()
except Exception as e:
print(e)
try:
three = WebDriverWait(self.browser, 5).until(
lambda y: y.find_element_by_xpath('//*[@id="altImages"]/ul/li[4]'))
ActionChains(self.browser).click_and_hold(on_element=three).perform()
for y in [0, 10, 20, 30, 40, 50, 50, 50, 40, 30, 20, 10, 0]:
ActionChains(self.browser).move_by_offset(xoffset=0, yoffset=y).perform()
ActionChains(self.browser).release().perform()
except Exception as e:
print(e)
except TimeoutException as e:
print("timeout")
self.browser.execute_script("window.stop()")
眼明手快的老铁可能已经发现了,分了X
轴和Y
轴,这是因为要模拟鼠标滑过这些缩略图,而这些缩略图,有的是在左侧竖着排列,有的是在底部横着排列,所以,要写不同的try
,不同的try
又对应起始不同的li
标签,所以,大概有四分之三的步骤是在浪费时间,只有正确的四分之一的操作对应到了某个商品,如果爬取少量的数据,这玩意儿也差不多,但是要几千几万的爬,这效率就低太多了,难道就没有更效率的方法了吗?唉,头发好像就少了一些。。。
重新回到页面,继续分析,验证猜测,
翻遍了所有的请求,最后还是发现并猜想,既然这些数据没有异步加载,而是直接返回了数据,可能高清图片地址就隐藏在某个js
里面,只不过需要鼠标滑过去触发才能显示,
因为之前写过几个亚马逊的爬虫,所以我清楚的之后,亚马逊的图片命名有一个规律,那就是相同商品高清图片地址像素的大小相同,切后缀是统一的,所以我打算搜索一下._AC_SL1000_.jpg
检测一下我的猜想
果然,天无绝人之路,数据已经在响应里面了,而且经过前后分析,我发现数据就是在这个方法里面,那我又该通过什么方式获取这些数据呢?
回到页面,重新搜索一下,看看数据在不在标签里面,xpath
能搞不能?
开心一刻!
xpath能拿到数据了,但是需要的高清图地址又该怎么获取呢?有头绪吗?冥想中。。。
管他三七二十一,先把获取到的数据打印出来看一看再说:
hdimg_js_str = response.xpath('//*[@id="imageBlock_feature_div"]/script[1]/text()').extract_first()
是不是发现,打印出来的数据,还是跟网页上面的一样,一行一行的,还有空格和换行呢?这该怎么搞呢?
还能怎么办,整理数据呗!
hdimg_js_str = str(hdimg_js_str).replace(" ", "").replace("\n", "").replace("\r", "")
嗯嗯,这是一个大的字符串,我需要的数据在哪儿呢?
数据已经能够拿到了,要提炼出来高清图地址,看来只能拿出我的re来获取了,反反复复的尝试:把当前四个数据正则出来很简单,回头一想,不同的商品有不同数量的图片,那就是正则直接从字符串中获取图片地址就不科学了,你用match,search,findall,哪个都不合适呀,怎么办,怎么办?
咦,数据在colorImages
字典里面,我可以先用正则获取这个大字典的字符串,然后转成字典,遍历字典应对不同数量的图片地址,这种方式它不香吗,搞起来。。。
先正则获取字典字符串:
reg = re.compile(".*data.*({\'colorImages\'.*),\'colorToAsin\'.*")
hdimg_str = reg.search(hdimg_js_str).group(1)
这样,就能获取到里面colorImages
的字符串了,现在,需要把它改造成一个字典的样子,
hdimg_str = str(hdimg_str).replace("'", "\"") + "}"
现在它已经是一个字典样子的字符串了,那怎样才能把一个字符串转变成一个字典呢?json
就该出马了
hdimg_dict = json.loads(hdimg_str, encoding="utf-8")
打印一下试试,一个字典也是一个json,那获取数据不要太舒服了,
hdimgs = "" # 定义一个空字符串,用于存储图片地址
for img_url in hdimg_dict["colorImages"]["initial"]:
hdimgs = hdimgs + img_url["hiRes"] + " | "
# 去除最后多出来的空格和竖线符号
main_hdimgs = hdimgs[:-3]
item["main_hdimgs"] = main_hdimgs
这样一来,selenium
里面的那些try
用来模拟鼠标滑动的语句就都可以删除了,只用它打开页面,加载完之后直接返回数据就可以了。
try:
self.browser.get(request.url)
self.browser.execute_script('window.scrollTo(0, 300)')
except TimeoutException as e:
print("timeout", e)
self.browser.execute_script("window.stop()")
time.sleep(random.random() * 1)
return HtmlResponse(url=self.browser.current_url, body=self.browser.page_source, encoding="utf-8",
request=request)
最后,来一组爬取好的数据镇楼!