Advertisement

当当网书籍封面爬取

阅读量:

当当网书籍封面爬取

我刚入门,在互联网领域算是个新手。最近才开始接触爬虫技术,并在今天尝试进行了一次初步实践——从京东平台获取了Python相关书籍的封面信息。我也参考了一些网上的文章思路,并在此基础上进行了创新性操作而非完全照搬他人方案。”

在当当网上输入'Python'后可以看到大量搜索结果(共计57页),作为一个新手用户首先要做的就是从这些结果中快速定位到目标书籍信息。接着,在网页界面右键点击页面并查看其源代码(如果无法直接找到封面图片链接则可以通过右键选择"查看"选项并在弹出窗口中定位到对应的元素)。以下代码展示了两本书封面图片的具体链接位置:

复制代码
>                            <li ddt-pit="1" class="line1" id="p24003310">
>                    <a title=" Python编程 从入门到实践"  ddclick="act=normalResult_picture&pos=24003310_0_1_q" class="pic" name="itemlist-picture"  dd_name="单品图片" href="http://product.dangdang.com/24003310.html"  target="_blank" >
>                    <img src='http://img3m0.ddimg.cn/67/4/24003310-1_b_7.jpg' alt=' Python编程 从入门到实践' /></a><p class="name" name="title" >
>                    <a title=" Python编程 从入门到实践【图灵程序设计丛书】Python3.5编程入门图书 机器学习 数据处理 网络爬虫热门编程语言 从基本概念到完整项目开发 帮助零基础读者迅速掌握Python编程 附赠源代码文件" href="http://product.dangdang.com/24003310.html" ddclick="act=normalResult_title&pos=24003310_0_1_q" name="itemlist-title" dd_name="单品标题" target="_blank" > <font class="skcolor_ljg">Python</font>编程 从入门到实践【图灵程序设计丛书】Python3.5编程入门图书 机器学习 数据处理 网络爬虫热门编程语言 从基本概念到完整项目开发 帮助零基础读者迅速掌握Python编程 附赠源代码文件</a></p><p class="detail" >上到有编程基础的程序员,下到10岁少年,想入门Python并达到可以开发实际项目的水平,本书是读者*! 本书是一本全面的从入门到实践的Python编程教程,带领读者快速掌握编程基础知识、编写出能解决实际问题的代码并开发复杂项目。 书中内容分为基础篇和实战篇两部分。基础篇介绍基本的编程概念,如列表、字典、类和循环,并指导读者编写整洁且易于理解的代码。另外还介绍了如何让程序能够与用户交互,以及如何在代码运行前进行测试。实战篇介绍如何利用新学到的知识开发功能丰富的项目:2D游戏《外星人入侵》,数据可视化实战,Web应用程序。</p><p class="price" > <span class="search_now_price">&yen;62.00</span><a class="search_discount" style="text-decoration:none;">定价:</a><span class="search_pre_price">&yen;89.00</span><span class="search_discount">&nbsp;(6.97折) </span></p><div class="lable_label"><span class="new_lable" y=""></span></div><p class="search_star_line" ><span class="search_star_black"><span style="width: 90%;"></span></span><a href="http://product.dangdang.com/24003310.html?point=comment_point" target="_blank" name="itemlist-review" dd_name="单品评论" class="search_comment_num" ddclick="act=click_review_count&pos=24003310_0_1_q">60044条评论</a></p><span class="tag_box"></span><p class="search_book_author"><span>[美]<a href='http://search.dangdang.com/?key2=埃里克·马瑟斯&medium=01&category_path=01.00.00.00.00.00' name='itemlist-author' dd_name='单品作者' title='[美]埃里克·马瑟斯(Eric Matthes)'>埃里克·马瑟斯</a>(<a href='http://search.dangdang.com/?key2=Eric&medium=01&category_path=01.00.00.00.00.00' name='itemlist-author' dd_name='单品作者' title='[美]埃里克·马瑟斯(Eric Matthes)'>Eric</a> <a href='http://search.dangdang.com/?key2=Matthes&medium=01&category_path=01.00.00.00.00.00' name='itemlist-author' dd_name='单品作者' title='[美]埃里克·马瑟斯(Eric Matthes)'>Matthes</a>)</span><span > /2016-07-01</span><span>  /<a href='http://search.dangdang.com/?key=&key3=%C8%CB%C3%F1%D3%CA%B5%E7%B3%F6%B0%E6%C9%E7&medium=01&category_path=01.00.00.00.00.00' name='P_cbs' dd_name='单品出版社' title='人民邮电出版社'>人民邮电出版社</a></span><div class="shop_button"><p class="bottom_p"><a  class='search_btn_cart ' name='Buy' dd_name='加入购物车' href='javascript:AddToShoppingCart(24003310)' ddclick='act=normalResult_addToCart&pos=24003310_0_1_q'>加入购物车</a><a class='search_btn_collect' name='collect' dd_name='加入收藏' id="lcase24003310" href="javascript:void(0);" name="Sc" ddclick='act=normalResult_favor&pos=24003310_0_1_q'>收藏</a></p></div>                </li>
>  
>  
>       
>       
>       
>       
>  
>
复制代码
                            <li ddt-pit="2" class="line2" id="p25576578">
                <a title=" Python学习手册(原书第5版)"  ddclick="act=normalResult_picture&pos=25576578_1_1_q" class="pic" name="itemlist-picture"  dd_name="单品图片" href="http://product.dangdang.com/25576578.html"  target="_blank" >
                <img data-original='http://img3m8.ddimg.cn/27/32/25576578-1_b_5.jpg' src='images/model/guan/url_none.png' alt=' Python学习手册(原书第5版)' /></a><p class="name" name="title" >
                <a title=" Python学习手册(原书第5版)Python入门必读之作,位列美亚软件编程畅销榜首,《Python编程》姊妹篇 覆盖Python 3.3和Python 2.7两个版本,详细讲解各种语言特性,并新增大量示例" href="http://product.dangdang.com/25576578.html" ddclick="act=normalResult_title&pos=25576578_1_1_q" name="itemlist-title" dd_name="单品标题" target="_blank" > <font class="skcolor_ljg">Python</font>学习手册(原书第5版)Python入门必读之作,位列美亚软件编程畅销榜首,《Python编程》姊妹篇 覆盖Python 3.3和Python 2.7两个版本,详细讲解各种语言特性,并新增大量示例</a></p><p class="detail" >本书根据Python专家Mark Lutz的著名培训课程编写而成,是易于掌握和自学的Python语言教程。书中以目前主流的Python 3.X为主,同时兼顾Python 2.X的内容,全面、系统讲解Python语言核心知识,每个知识都会以知识点、思想、示例代码的方式详细展开,由浅入深,循序渐进。同时每章都配有章后习题、编程练习及详尽的解答,并且还配有大量注释、示例和图表,便于你学习新的技能和巩固加深自己的理解。无论你从事哪个领域,本书都为你提供了未来全部Python工作的必备知识。</p><p class="price" > <span class="search_now_price">&yen;173.00</span><a class="search_discount" style="text-decoration:none;">定价:</a><span class="search_pre_price">&yen;219.00</span><span class="search_discount">&nbsp;(7.9折) </span></p><div class="lable_label"><span class="new_lable" y=""></span></div><p class="search_star_line" ><span class="search_star_black"><span style="width: 100%;"></span></span><a href="http://product.dangdang.com/25576578.html?point=comment_point" target="_blank" name="itemlist-review" dd_name="单品评论" class="search_comment_num" ddclick="act=click_review_count&pos=25576578_1_1_q">113条评论</a></p><span class="tag_box"></span><p class="search_book_author"><span>[美]<a href='http://search.dangdang.com/?key2=马克·卢茨&medium=01&category_path=01.00.00.00.00.00' name='itemlist-author' dd_name='单品作者' title='[美]马克·卢茨'>马克·卢茨</a></span><span > /2018-11-05</span><span>  /<a href='http://search.dangdang.com/?key=&key3=%BB%FA%D0%B5%B9%A4%D2%B5%B3%F6%B0%E6%C9%E7&medium=01&category_path=01.00.00.00.00.00' name='P_cbs' dd_name='单品出版社' title='机械工业出版社'>机械工业出版社</a></span><div class="shop_button"><p class="bottom_p"><a  class='search_btn_cart ' name='Buy' dd_name='加入购物车' href='javascript:AddToShoppingCart(25576578)' ddclick='act=normalResult_addToCart&pos=25576578_1_1_q'>加入购物车</a><a class='search_btn_collect' name='collect' dd_name='加入收藏' id="lcase25576578" href="javascript:void(0);" name="Sc" ddclick='act=normalResult_favor&pos=25576578_1_1_q'>收藏</a></p></div>                </li>

图片链接位置如下:
一张图片位于位置:
<img src="https://img3m0.ddimg.cn/67/4/24003310-1_b_7.jpg" alt="《Python编程入门经典教材》 />
另一张图片位于位置:
《Python学习指南(第5版)》

在网页上观察后,进入python开始写代码啦~~

该页面的链接地址为http://search.dangdang.com/?key=Python&act=输入字段&page_index=1

复制代码
    import requests
    url=r'http://search.dangdang.com/?key=python&act=input&page_index=1'
    response=requests.get(url)
    text=response.text
    text

获取到文本即为之前在网页上看到的源代码。可以看出的是,在imgxxx这样的格式中存在图像连接。

复制代码
    import re
    re.findall("<img.*?>",text)
    len(re.findall("<img.*?>",text))

一页有60本书的信息,匹配出了65项,查看匹配成功的部分,其中多余的5项为:

能够更精确地表示为这样的格式。这额外的5项中没有包含.jpg后缀,并且无法采用该种格式形式;因此我们需要将正则式进行调整。

复制代码
    fit=re.findall("<img.*?jpg.*?>",text)
    len(fit)

检测一下列表 fit 有60个元素。
现在 fit 中的元素形如以下两个例子:

其中一张图像[Python 编程从入门到实践](Python 编程从入门到实践),另一张图像[Python 学习手册(第五版)](Python 学习手册(第五版))。

还需进一步提取以http开头的链接,并同时提取alt字段后的书名。创建两个列表links和names,并遍历fit中的每个元素,在其中会获取到对应的链接与书名并存入上述两个列表中。

复制代码
    links=[]
    names=[]
    for i in fit:
    links.append(re.findall("http.*?jpg",i))
    name=re.findall("alt.*'",i)
    name=re.sub("^alt=' ","",name[0])
    name=re.sub("'$","",name)
    names.append(name)

建议先检查一下(links和names各有60个元素),以确保是否符合预期的结果。下一步需要同时遍历这两个列表来提取每一张图片,并从两个列表中提取每一张图片。为了实现这一目标,请编写如下的代码:

复制代码
    for i in range(len(links)):
    print("Downloding the Picture of "+names[i]+" from: "+links[i][0])
    pic=requests.get(links[i][0])
    file=open(names[i]+".jpg","xb") #一定要事先创建一个文件夹,并一定记得指定为默认工作目录!!!图片将保存到文件夹里。否则,上千张图片将占据你原来的工作目录。。。。。。
    file.write(pic.content)
    file.close()

我的默认工作目录设置在桌面位置,在某次调试过程中无意间运行了上述代码后发现大量图片开始铺展开来一浪接一浪地占据着电脑桌面的空间。因此需要提前准备好一个合适的文件夹存放这些图片。(真诚的语气)

在这里插入图片描述

执行代码后,我新建了一个名为pic的文件夹,在里面已经有60张图片了。按时间排序后的位置与网页上的排列一致。

在这里插入图片描述

接下来实现爬取57页的封面图片。首先观察每一页的URL的规律:

http://search.dangdang.com/?key/python&act/input&page_number=1
http://search.dangdang.com/?key/python&act/input&page_number=2
\vdots
[http://search.dangdang.com/?key/python&act/input&page_number=57](http://search.dangd ang.com/?key/python&act/input&page_number#57)

每一页的独特之处在于其page_index值所代表的数字。因此,在处理时可以采用一个循环逐个处理每个数字进行字符串拼接操作即可完成任务。代码中加入了变量n来统计每一页的匹配数量。执行后观察到1至56页共有60个匹配,第57页仅有9个匹配。

复制代码
    links=[]
    names=[]
    n=[]
    print("Loading...")
    for i in range(57):
    url=r'http://search.dangdang.com/?key=python&act=input&page_index='+str(i+1)
    response=requests.get(url)
    text=response.text
    fit=re.findall("<img.*?jpg.*?>",text)
    n.append(len(fit))
    for i in fit:
        links.append(re.findall("http.*?jpg",i))
        name=re.findall("alt.*'",i)
        name=re.sub("^alt=' ","",name[0])
        name=re.sub("'$","",name)
        names.append(name)

len(links)
Out[53]: 3369
len(names)
Out[54]: 3369

有3369条书籍信息

在 links 和 names 列表中存储了57页的图书链接及其书名。随后,在处理每一页时会执行以下操作:首先下载对应的图片文件并将其保存到指定目录;接着提取书籍的相关信息并存储至指定列表中。继续运行整个脚本流程

复制代码
    for i in range(len(links)):
    print("Downloding the Picture of "+names[i]+" from: "+links[i][0])
    pic=requests.get(links[i][0])
    file=open(names[i]+".jpg","xb")
    file.write(pic.content)
    file.close()

一旦运行完成之后爬虫便达到了预期目标;然而当数据量显著增加时会导致系统出现若干潜在问题。

File “”, line 4, in
该文件被打开为二进制模式
FileExistsError: [Errno 17] File already exists: 'Python深度学习.jpg'

FileExistsError 是指尝试打开一个已存在的文件时所引发的异常错误。具体来说,在使用 Python 的 file 模块进行操作时,默认采用的是 write mode(‘w’),这种模式下如果无法创建新文件(即该文件已经存在),则会抛出 FileExistsError 错误;而如果指定为 exclusive write mode(‘x’)则会强制删除现有文件后再进行操作。因此,在书名重复的情况下会触发上述错误提示信息。为了修复这一问题,在我的代码中将修改默认的打开方式:将之前的 exclusive write mode 更改为 standard write mode(‘w’)。这样做的效果是:当无法找到该文件时会直接创建新文件;如果该文件已经存在,则会将现有内容完全重写掉(理论上来说书名相同的话封面应当是相同的吧)。关于不同打开模式的具体区别与应用场景,建议参考下方这篇博客文章:

file=open(names[i]+".jpg",“xb”)
\downarrow
file=open(names[i]+".jpg",“wb”)

再次运行时出现了一个OSError错误,请您注意检查文件路径是否正确?原因在于书名中存在星号()这一特殊字符,在打开操作中会被系统识别并抛出相应的错误提示。目前页面越往后提取出的书名包含了很多杂乱的信息。。由于我尚未考虑如何进行后续的数据清洗工作(即如何处理这些异常情况),因此目前仅采取了简单的解决措施——将所有星号替换为空格以避免冲突。为了简化处理流程,在此阶段我对代码进行了初步优化,并暂时搁置更复杂的解决方案。在完成当前任务后我会着手制定更详细的处理计划)。为了确保代码能够顺利运行,请您先完成以下步骤:将星号()、连接符('|')、问号('?')以及成对出现的冒号(':')等特殊字符逐一替换成空格或其他无意义字符以避免类似的问题再次发生

复制代码
    for i in range(len(names)):
    names[i]=re.sub("[\*\|:\?]"," ",names[i])

再次运行后出现了新的错误 FileNotFoundError。理论上使用覆盖写模式不应该出现这种错误。检查了一下导致错误的书名发现其中有一个特殊字符 '/' 这个字符通常会出现在文件路径中 因此可能导致无法正确打开文件的问题尚不清楚如何详细解释 只需将斜杠替换为空格即可继续操作。

在模块中打开文件 "Python基础教程 第2版 编程从入门到实践 核心语言开发指南 自学教程基础书籍 程序设计/软件开发教材 代码大全入.jpg" 时发生以下错误:

错误号为2的未找到指定的文件或目录:'Python基础教程 第2版 编程从入门到实践 核心语言开发指南 自学教程基础书籍 程序设计/软件开发教材 代码大全入.jpg'

已经不再出现错误信息。检查一下发现:列表 n 的最后一位数值由 9 更改为 7;同时 links 和 names 的元素数量分别减少了 2 个。可以看出,在这期间网页上与 Python 相关的书籍数量有所调整

print(n[56],len(links),len(names))
7 3367 3367

然而,在线内容往往不断更新换代。昨晚编写好了爬虫代码运行未报错错误。今天在撰写这篇记录时发现使用旧版正则式反而增加了两个匹配项其中 today 的改动较为微小。因此我的爬虫实践经验表明具体问题需具体分析这种灵活多变的特点是很值得借鉴的经验之所在。下载完成后即可欣赏图片~~~值得注意的是因为是覆盖写法保存下来的图片数量仅为3025张远低于预期的书目总数3367条

在这里插入图片描述

附上完整的代码:

复制代码
    import time
    start=time.perf_counter()
    import requests
    import re
    links=[]
    names=[]
    n=[]
    response_time=0
    print("Loading...")
    for i in range(57):
    url=r'http://search.dangdang.com/?key=python&act=input&page_index='+str(i+1)
    t0=time.perf_counter()
    response=requests.get(url)
    t1=time.perf_counter()
    response_time=response_time+t1-t0
    text=response.text
    fit=re.findall("<img.*?jpg.*?>",text)
    n.append(len(fit))
    for i in fit:
        links.append(re.findall("http.*?jpg",i))
        name=re.findall("alt.*'",i)
        name=re.sub("^alt=' ","",name[0])
        name=re.sub("'$","",name)
        names.append(name)
    for i in range(len(names)):
    names[i]=re.sub("[\*/\|:\?]"," ",names[i])
    t0=time.perf_counter()
    for i in range(len(links)):
    print("Downloding the Picture of "+names[i]+" from: "+links[i][0])
    pic=requests.get(links[i][0])
    file=open(names[i]+".jpg","wb")
    file.write(pic.content)
    file.close()
    t1=time.perf_counter()
    download_time=t1-t0
    end=time.perf_counter()
    print("所有图片已下载完成!")
    print("请求响应总时间:{}s".format(response_time))
    print("图片下载时间:{}s".format(download_time))
    print("运行时间:{}s".format(end-start))

增加了对网页发出请求并返回相应信息的时间监测功能。使用requests.get方法向网页发送HTTP请求并接收响应所需的时间总计26秒;而处理完所有3,367张图片的所有HTTP请求后的完整流程(包括响应与文件保存)所花费的时间总计120秒;整个程序运行完成所需的时间总计149秒。

在这里插入图片描述

全部评论 (0)

还没有任何评论哟~