最近读了一本书叫大明第一清官海瑞,所以打算再买一本书,所以就去当当网看了一些和张居正的数据,但是数据太多,所以就想用爬虫爬取一下。
页面分析
首先对我们需要访问的url进行访问
由响应码可知请求数据成功,当当书城中不加请求头,也能请求成功,接着可以打印一些响应内容看看页面是否有我们想要的数据,
由响应的内容可以知道,响应回来的页面数据,有我们需要的,那么接下来需要的就是解析
页面解析
像这种ul下面的数据,就是先获取所有的li标签然后再逐一拿取li中的数据,这里我们使用的是lxml库中的xpath语法规则
et = etree.HTML(rep.text)
li_list = et.xpath("//ul[@class='bigimg']/li")
# print(len(li_list)) #检查数据条数
for li in li_list:
# 书籍序号
book_no = li.xpath("./@ddt-pit")
# 书籍名称
book_name = ''.join(li.xpath("./p[1]/a//text()"))
# 书籍url
book_img_src = li.xpath("./a[1]/img/@src")
book_img = li.xpath("./a[1]/img/@data-original")
if len(book_img)==0:
book_img = book_img_src
# 书籍作者
book_author = li.xpath("./p[@class='search_book_author']/span[1]/a/text()")
# 出版时间
book_time = li.xpath("./p[@class='search_book_author']/span[2]/text()")
# 出版社
book_press = li.xpath("./p[@class='search_book_author']/span[3]/a/text()")
# 书籍价格
book_price = li.xpath("./p[@class='price']/span[1]/text()")
# 书籍介绍
book_detail = li.xpath("./p[@class='detail']/text()")
这样就能拿到数据了,但是我们不止爬取一个页面,需要爬取多个页面,那么我们就需要去发现一个规律看看页面怎么变化的。
当点击第二页的时候,发现url多了一个请求参数,再多点几个页面的时候发现,就是这个参数在控制页面,那么我们就可以利用for循环来改变请求的url
for i in range(1,100):
t.submit(get_dang_dang,f"https://search.dangdang.com/?key=%D5%C5%BE%D3%D5%FD&act=input&page_index={i}",i).add_done_callback(count_page)
为了提高速度我们采用了多线程把请求url放到线程池中去,add_done_callback(count_page)是为了得到解析过后的返回值
#输出每页数据
def count_page(res):
print(res.result())
return res.result()
我们对解析后的数据做了封装,解析完一个书籍就封装成字典类型添加到一个列表中,这样解析完一个页面就会将这个页面的所有数据返回。
#发送网络请求
def get_dang_dang(url,page_num):
book_list=[]
book_list.append(f"第{page_num}页")
rep=requests.get(url)
if rep.status_code==200:
# print(rep.status_code)
# 打印响应内容
# print(rep.text) #爬取内容存在返回数据中
et = etree.HTML(rep.text)
li_list = et.xpath("//ul[@class='bigimg']/li")
# print(len(li_list)) #检查数据条数
for li in li_list:
# 书籍序号
book_no = li.xpath("./@ddt-pit")
# 书籍名称
book_name = ''.join(li.xpath("./p[1]/a//text()"))
# 书籍url
book_img_src = li.xpath("./a[1]/img/@src")
book_img = li.xpath("./a[1]/img/@data-original")
if len(book_img)==0:
book_img = book_img_src
# 书籍作者
book_author = li.xpath("./p[@class='search_book_author']/span[1]/a/text()")
# 出版时间
book_time = li.xpath("./p[@class='search_book_author']/span[2]/text()")
# 出版社
book_press = li.xpath("./p[@class='search_book_author']/span[3]/a/text()")
# 书籍价格
book_price = li.xpath("./p[@class='price']/span[1]/text()")
# 书籍介绍
book_detail = li.xpath("./p[@class='detail']/text()")
# 书籍信息封装
dic ={
"book_name":book_name,
"book_img" :"http:"+book_img[0],
"book_author" : ';'.join(book_author),
"book_time" : "".join(book_time),
"book_press" : "".join(book_press),
"book_price" : "".join(book_price),
"book_detail" : "".join(book_detail)
}
book_list.append(dic)
# print(dic)
else:
print("url不存在请求失败")
return book_list
爬取成功
完整代码展示
#发送网络请求
def get_dang_dang(url,page_num):
book_list=[]
book_list.append(f"第{page_num}页")
rep=requests.get(url)
if rep.status_code==200:
# print(rep.status_code)
# 打印响应内容
# print(rep.text) #爬取内容存在返回数据中
et = etree.HTML(rep.text)
li_list = et.xpath("//ul[@class='bigimg']/li")
# print(len(li_list)) #检查数据条数
for li in li_list:
# 书籍序号
book_no = li.xpath("./@ddt-pit")
# 书籍名称
book_name = ''.join(li.xpath("./p[1]/a//text()"))
# 书籍url
book_img_src = li.xpath("./a[1]/img/@src")
book_img = li.xpath("./a[1]/img/@data-original")
if len(book_img)==0:
book_img = book_img_src
# 书籍作者
book_author = li.xpath("./p[@class='search_book_author']/span[1]/a/text()")
# 出版时间
book_time = li.xpath("./p[@class='search_book_author']/span[2]/text()")
# 出版社
book_press = li.xpath("./p[@class='search_book_author']/span[3]/a/text()")
# 书籍价格
book_price = li.xpath("./p[@class='price']/span[1]/text()")
# 书籍介绍
book_detail = li.xpath("./p[@class='detail']/text()")
# 书籍信息封装
dic ={
"book_name":book_name,
"book_img" :"http:"+book_img[0],
"book_author" : ';'.join(book_author),
"book_time" : "".join(book_time),
"book_press" : "".join(book_press),
"book_price" : "".join(book_price),
"book_detail" : "".join(book_detail)
}
book_list.append(dic)
# print(dic)
else:
print("url不存在请求失败")
return book_list
#下载书籍
def download_img(res):
for dic in res.result()[1:]:
print(dic["book_img"])
#输出每页数据
def count_page(res):
print(res.result())
return res.result()
#第一页测试
def test_page():
book_list = get_dang_dang("https://search.dangdang.com/?key=%D5%C5%BE%D3%D5%FD&act=input&page_index=1",1)
for dic in book_list[1:]:
print(dic["book_img"])
if __name__ =="__main__":
# test_page()
with ThreadPoolExecutor(50) as t:
for i in range(1,100):
t.submit(get_dang_dang,f"https://search.dangdang.com/?key=
%D5%C5%BE%D3%D5%FD&act=input&page_index={i}",i).add_done_callback(count_page)
代码还有可以完善的地方,页面数量是由我们自己定的其实页还有其他办法,比如去获取最后一页数值,作为循环的参数,也可以加入协程,还有就是数据没有保存,按照我返回的这种数据格式建议保存为json数据格式。
欢迎关注微信公众号,定期推送干货