Python Scrapy实战:京东商城数据爬取进阶教程
本文深入讲解使用Python Scrapy框架爬取京东商城的进阶技巧。内容涵盖构造奇数页请求、解析首屏数据、处理Ajax异步加载的后半部分商品信息,以及通过Meta传递参数。同时提供断点续爬、下载延迟、随机延迟、忽略Robots协议及并发控制等settings.py配置技巧,帮助开发者高效获取商品详情并避免被封禁。
前言
在之前的文章中,我们已经介绍了如何获取链接和参数,具体细节可参考《Python爬取京东商城普通篇》。本文将重点介绍如何利用Python爬虫框架Scrapy来爬取京东商城的数据,下面直接开始详细介绍。
代码详解
1、首先构造请求。这里使用scrapy.Request方法,该方法默认调用start_urls来构造请求。如果需要改变默认的请求方式,必须重载该方法。该方法的返回值必须是一个可迭代对象,通常使用yield返回。
代码如下:
def start_requests(self):
for i in range(1,101):
page=i*2-1 #这里是构造请求url的page,表示奇数
url=self.start_url+str(page)
yield scrapy.Request(url,meta={'search_page':page+1},callback=self.parse_url) #这里使用meta想回调函数传入数据,回调函数使用response.meta['search-page']接受数据
接下来是网页解析部分。从上面的代码可以看出,解析回调函数是parse_url,因此需要在此函数中解析网页。与之前提到的内容一致,这里得到的url仅包含前半部分信息。如果需要获取后半部分信息,还需要再次发起请求。这里需要注意一个技巧:通常先解析出一个数据数组,不要急于取出第一个元素,而是先用if语句进行判断。因为如果得到的是空数组[],直接取出[0]会报错,这是一种避免报错的方法。
代码如下:
def parse_url(self,response):
if response.status==200: #判断是否请求成功
# print response.url
pids = set() #这个集合用于过滤和保存得到的id,用于作为后面的ajax请求的url构成
try:
all_goods = response.xpath("//div[@id='J_goodsList']/ul/li") #首先得到所有衣服的整个框架,然后从中抽取每一个框架
for goods in all_goods: #从中解析每一个
# scrapy.shell.inspect_response(response,self) #这是一个调试的方法,这里会直接打开调试模式
items = JdSpiderItem() #定义要抓取的数据
img_url_src = goods.xpath("div/div[1]/a/img/@src").extract() # 如果不存在就是一个空数组[],因此不能在这里取[0]
img_url_delay = goods.xpath(
"div/div[1]/a/img/@data-lazy-img").extract() # 这个是没有加载出来的图片,这里不能写上数组取第一个[0]
price = goods.xpath("div/div[3]/strong/i/text()").extract() #价格
cloths_name = goods.xpath("div/div[4]/a/em/text()").extract()
shop_id = goods.xpath("div/div[7]/@ data-shopid").extract()
cloths_url = goods.xpath("div/div[1]/a/@href").extract()
person_number = goods.xpath("div/div[5]/strong/a/text()").extract()
pid = goods.xpath("@data-pid").extract()
# product_id=goods.xpath("@data-sku").extract()
if pid:
pids.add(pid[0])
if img_url_src: # 如果img_url_src存在
print img_url_src[0]
items['img_url'] = img_url_src[0]
if img_url_delay: # 如果到了没有加载完成的图片,就取这个url
print img_url_delay[0]
items['img_url'] = img_url_delay[0] # 这里如果数组不是空的,就能写了
if price:
items['price'] = price[0]
if cloths_name:
items['cloths_name'] = cloths_name[0]
if shop_id:
items['shop_id'] = shop_id[0]
shop_url = "https://mall.jd.com/index-" + str(shop_id[0]) + ".html"
items['shop_url'] = shop_url
if cloths_url:
items['cloths_url'] = cloths_url[0]
if person_number:
items['person_number'] = person_number[0]
# if product_id:
# print "************************************csdjkvjfskvnk***********************"
# print self.comments_url.format(str(product_id[0]),str(self.count))
# yield scrapy.Request(url=self.comments_url.format(str(product_id[0]),str(self.count)),callback=self.comments)
#yield scrapy.Request写在这里就是每解析一个键裤子就会调用回调函数一次
yield items
except Exception:
print "********************************************ERROR**********************************************************************"
yield scrapy.Request(url=self.search_url.format(str(response.meta['search_page']),",".join(pids)),callback=self.next_half_parse) #再次请求,这里是请求ajax加载的数据,必须放在这里,因为只有等到得到所有的pid才能构成这个请求,回调函数用于下面的解析
2、从上述代码的最后部分可以看出,最后一步是解析Ajax加载的网页。这里调用了next_half_parse函数,其解析方式与解析前半部分网页相同。需要注意的是,如果前面定义的数据没有搜索完毕,不能使用yield items,必须将items通过meta传入下一个回调函数,继续完善后才能yield items,这里就不需要了。
代码如下:
#分析异步加载的网页
def next_half_parse(self,response):
if response.status==200:
print response.url
items=JdSpiderItem()
#scrapy.shell.inspect_response(response,self) #y用来调试的
try:
lis=response.xpath("//li[@class='gl-item']")
for li in lis:
cloths_url=li.xpath("div/div[1]/a/@href").extract()
img_url_1=li.xpath("div/div[1]/a/img/@src").extract()
img_url_2=li.xpath("div/div[1]/a/img/@data-lazy-img").extract()
cloths_name=li.xpath("div/div[4]/a/em/text()").extract()
price=li.xpath("div/div[3]/strong/i/text()").extract()
shop_id=li.xpath("div/div[7]/@data-shopid").extract()
person_number=li.xpath("div/div[5]/strong/a/text()").extract()
if cloths_url:
print cloths_url[0]
items['cloths_url']=cloths_url[0]
if img_url_1:
print img_url_1[0]
items['img_url']=img_url_1
if img_url_2:
print img_url_2[0]
items['img_url']=img_url_2[0]
if cloths_name:
items['cloths_name']=cloths_name[0]
if price:
items['price']=price[0]
if shop_id:
items['shop_id']=shop_id[0]
items['shop_url']="https://mall.jd.com/index-" + str(shop_id[0]) + ".html"
if person_number:
items['person_number']=person_number[0]
yield items #又一次的生成,这里是完整的数据,因此可以yield items
except Exception:
print "**************************************************"
3、此外,这里还涉及到了请求池的设置和MySQL存储,并未使用IP代理。这部分内容在我之前的博客中已有讲解,此处不再赘述。
想看源代码的朋友请
点击这里 或者 本地下载
小技巧
- 人们常抱怨为什么爬虫在中途断开后需要从头开始爬,而不能从断点处继续。这里提供一种方法:在配置文件settings.py中加入
JOBDIR=file_name,这里的file_name是一个文件的名字。 - 设置下载延迟以防止被屏蔽:
DOWNLOAD_DELAY = 2用于设置每次请求的间隔时间;RANDOMIZE_DOWNLOAD_DELAY = True用于随机设置延迟时间,在设定时间的0.5到1.5倍之间,这样可以更有效地防止被屏蔽,通常是配套使用的。 ROBOTSTXT_OBEY = False:这里表示不遵循robots.txt文件,默认值为True表示遵循,这里将其改为False。CONCURRENT_REQUESTS:设置最大请求数,默认值为16,我们可以根据自己电脑的配置改大一些,以加快请求速度。
总结
以上就是本文的全部内容,希望本文的内容对大家学习或使用Python能带来一定的帮助。如果有疑问,大家可以留言交流,谢谢大家对本站的支持。
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













