目标:
抓取京东图书包含图书的名字、封面图片、图书url地址、出版社、出版时间、价格、图书所属大分类、图书所属的小分类,分类的url地址,数据保存在本地
思路
- 由于爬取的数量较多,所以这里使用scrapy框架对数据进行抓取
- 找到start_url,链接为:https://book.jd.com/booksort.html
- 将数据抓取完毕之后保存在本地,写好item_pepiline
代码
# -*- coding: utf-8 -*-
import scrapy
import json
from copy import deepcopy
class JdSpider(scrapy.Spider):
name = 'jd'
allowed_domains = ['jd.com', 'list.jd.com', 'rms.shop.jd', 'p.3.cn'] # 增加列表页中的地址
start_urls = ['https://book.jd.com/booksort.html']
def parse(self, response):
dt_list = response.xpath("//div[@class='mc']/dl/dt") # 大分类列表
for dt in dt_list:
item = {}
item["b_cate"] = dt.xpath("./a/text()").get()
em_list = dt.xpath("./following-sibling::dd[1]/em") # 小分类分组
for em in em_list:
item["l_cate"] = em.xpath("./a/text()").get()
item["l_book_url"] = em.xpath("./a/@href").get() # 小分类书籍url地址
if item["l_book_url"] is not None:
item["l_book_url"] = response.urljoin(item["l_book_url"])
# 构建请求,将获取书籍详情页
yield scrapy.Request(
item["l_book_url"],
callback=self.parse_book_detail,
meta={"item": deepcopy(item)},
# dont_filter=True
)
def parse_book_detail(self, response): # 解析列表页
item = response.meta["item"]
li_list = response.xpath("//div[@id='plist']//li")
for li in li_list:
item["book_name"] = li.xpath(".//div[@class='p-name']/a/em/text()").get().strip() # 书籍名称
item["book_img_url"] = li.xpath(".//div[@class='p-img']//img/@src").get()
if item["book_img_url"] is not None:
item["book_img_url"] = response.urljoin(item["book_img_url"]) # 书籍图片链接
else:
item["book_img_url"] = li.xpath(".//div[@class='p-img']/a/img/@data-lazy-img").get()
item["book_img_url"] = response.urljoin(item["book_img_url"])
item["book_detail_url"] = li.xpath(".//div[@class='p-name']/a/@href").get() # 售卖页面
if item["book_detail_url"] is not None:
item["book_detail_url"] = response.urljoin(item["book_detail_url"])
item["pub_time"] = li.xpath(".//div[@class='p-bookdetails']//span[@class='p-bi-date']//text()").get().strip()
sale_id = li.xpath("./div/@venderid").get()
# 获取带有售卖书的店名的url地址
json_sale_url = "https://rms.shop.jd.com/json/pop/shopInfo.action?ids={}".format(sale_id) # 获得售卖商店的url地址
# 获取图书价格的地址
book_price_id = li.xpath("./div/@data-sku").get() # 图书id
book_price_url = "https://p.3.cn/prices/mgets?&ext=11101100&" \
"pin=&type=1&area=4_50953_50979_0&skuIds=J_{}".format(book_price_id) # 图书链接
yield scrapy.Request(
url=book_price_url,
callback=self.get_book_price,
meta={"item": deepcopy(item)}
)
# 构建获得售卖图书的函数
yield scrapy.Request(
url=json_sale_url,
callback=self.get_sale_shop,
meta={"item": deepcopy(item)}
)
def get_sale_shop(self, response):
item = response.meta["item"]
item["sale_shop"] = json.loads(response.text)[0]["name"]
def get_book_price(self, response):
item = response.meta["item"]
item["book_price"] = json.loads(response.text)[0]["op"]
print(item)
return item
最终效果图
心得与体会
在这里分享一下我在爬取的过程中所遇到的困难和解决方法吧
1. 首先是获取dt标签的兄弟标签dd时,突然忘记xpath的语法,于是就只能寻求万能的度娘,xpath方法:following-sibling::dd[1], 我可真机灵0.0
2. 获取到所有的大分类和小分类标题和小分类的书籍url地址后,构建解析书籍详情页的函数,却发现其中测试运行程序时,等了好一会都没有结果,搞得我还以为自己的代码写错了,又是加dont_filter=True,什么的,但都没有效果,而且构建的函数还没有结果,后面将自己在settings中写的LOG_LEVEL="WARNING"注释,在启动程序时,才发现程序一直在重定向到其他的url地址,所以我要做的就是什么也不做…(我太弱了TOT)
3. 再后面我再抓取图书价格时,明明xpath语法已经写对了,但是程序运行时却为None值,再element网页中可以看到价格,所以再观察网页源代码中却发现这个值时空的,所以他应该是以js渲染出来的,然后就在谷歌浏览器中搜索价格
发现确实时再一个json数据中,然后找到它所对应的url地址进行请求,发现规律每一本书的url地址是与它的id相对应。所以我们只需要找到它的id就可以了,在后续抓取图书售卖商店时也是进行相同的操作。
以上就是我所遇到的困难和解决方法,再写的每一个程序中我们都能够收获到许多知识,每天更进一步,加油