Python爬虫

本文介绍了一个使用Python的requests和BeautifulSoup库来爬取当当网24小时畅销书排行榜的爬虫程序。该程序能自动抓取书籍排名、名称、评论数等信息,并保存至CSV文件。

今天要做的是一个爬取当当网畅销书排行的爬虫,之后想看排行直接运行程序就可以看到啦,没有多余的信息,是不是很给力!

在前两次的爬虫编写过程中,思想都是把整个HTML文档看做一个很长很长的字符串,通过编写特定的正则表达式匹配我们需要的内容。这对于一般的内容不多的爬取需求是可以满足,但是一旦我们需要爬取的内容多了起来,正则表达式的模式就会变得相当复杂,可读性也不够好。那么有没有另外一种方法呢?答案是肯定的,这就是BeautifulSoup这个第三方库。

那么BeautifulSoup是做什么的呢?关于其详细功能,参阅官方文档,点击打开链接,这里只给出其主要思想:

Beautiful Soup 是一个可以从HTML或XML文件中提取数据的Python库。它能够通过你喜欢的转换器实现惯用的文档导航,查找,修改文档的方式。Beautiful Soup会帮你节省数小时甚至数天的工作时间。

简单来讲,Beautiful Soup将复杂HTML文档转换成一个复杂的树形结构,每个节点都是Python对象,通过对这些对象进行操作,就可以得到需要的内容。

另外,稍微提一下,该实例获取指定url的html文档使用了requests库,其原理和urllib.request类似:

[python] view plain copy

[python] view plain copy

    user_agent = 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)'  
    headers = {'User-Agent': user_agent}  
    r = requests.get(url, headers=headers)  
    html = r.text 

[python] view plain copy

得到一个html后,就可以使用soup = BeautifulSoup(html, ‘html.parser’),得到解析后的BeautifulSoup对象soup,可以对soup进行操作获取指定内容。

好了,具体的用法还是参考上面的官方文档,先步入正题,编写今天的爬虫吧:

1.首先,进入到当当图书畅销榜的网页当当图书近24小时畅销榜,右键查看源代码,找到我们关心的排行榜的位置:

这里我们关心的有:排名,书名,评论,作者,出版日期,出版社,价格。而这些信息都在特定的标签内,通过soup对象的方法方便将其一一找到。

2.根据网页源代码,所有的榜单内的图书信息均在

    标签内,这是我们关心的内容。在
      标签下,每个榜单内的图书都在
      • 标签下,具体信息对应相应的div标签。以排名信息为例,排名在标签
        (排名前四的数字是红色的)和
        里,因此使用正则表达式匹配’class’属性,其中list_num$表示属性值以list_num字符串开头。这样就找到了所有的排名的div标签,之后调用标签的get_text()方法即可得到排名的字符串。代码如下:
        [python] view plain copy

            def getBookInfo(html, lst):  
                soup = BeautifulSoup(html, 'html.parser')  
                tag_ul = soup.find('ul', attrs={'class': 'bang_list clearfix bang_list_mode'})  
                tag_li = tag_ul.find_all('li')  
                for book in tag_li:  
                book_info = {}  
                    book_rank = book.find('div', attrs={'class': re.compile('list_num$')})  
                .....  
                book_info.update({'排名': book_rank.get_text()[:-1]})  
                .....  
                lst.append(book_info)  
                 return lst  

        [python] view plain copy

        获取其它图书信 息的代码类似,这里就不再一一说明,详见后面的完整代码。^_^

        这里定义一个获取图书信息的函数,传入一个html和一个列表,每个图书的信息将使用字典类型存储,方便读取。调用字典的update({key:value})方法即可将键值对保存在字典中。利用for循环,每一个图书信息都保存完毕后,把代表这个图书的字典保存在lst中并返回,最后的得到的就是[{book1},{book2},….]。

        3.保存文件

        由于爬取的每本书包含的键都是相同的,因此将得到的列表保存在csv表格文件中比较清晰,也便于以后进行进一步的分析。python自带的csv库就可以解决这个问题,把数据写入csv文件的一般方法为:
        [python] view plain copy

        [python] view plain copy

            user_agent = 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)'  
            headers = {'User-Agent': user_agent}  
            r = requests.get(url, headers=headers)  
            html = r.text  

        [python] view plain copy

        这里需要解释的有:

        (1)使用with open()方法,在读写完成后会自动关闭文件;

        (2)参数path指的是文件的路径,’w’指的是操作文件的方法这里是写文件。而后面两个参数我开始是没有加的,最后出现了两个问题:encoding=’utf-8’不加的话会出现’gbk’编码问题,具体产生原因百度就好;newline=”“不加的话最后写入的表格中会有多余的空行。

        (3)由于爬取过程中需要写入多行数据,最后爬取的内容是列表元素为字典的列表,恰好csv.DictWriter(file, fieldnames)就是写入字典类型的数据,因此选择这个方法写文件。dictWriter.writeheader()就是写表头的,这里就是[‘排名’, ‘书名’, ‘作者’, ‘评论数’, ‘出版日期’, ‘出版社’, ‘售价’],下面的数据一一对应。dictWriter.writerows(lst)接收以字典为元素的list,每个字典是一行。

        4.爬取完整榜单

        上述过程爬取了给定的url,即排行榜首页的url。观察地址栏,榜单有25页,url为’http://bang.dangdang.com/books/bestsellers/01.00.00.00.00.00-24hours-0-0-1-(1-25)‘,
        [python] view plain copy

        [python] view plain copy

         user_agent = 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)'  
            headers = {'User-Agent': user_agent}  
            r = requests.get(url, headers=headers)  
            html = r.text  

        [python] view plain copy

        <span style="white-space:pre"></span>  
        

        这样就得到了所有的url信息,在这个循环下每次爬取一页,就可以爬取完整榜单。这里用print记录爬取的进度,出问题时也能及时发现。
        [python] view plain copy

            def main():  
                book_list = []  
                fieldnames = ['排名', '书名', '作者', '评论数', '出版日期', '出版社', '售价']  
                path = 'C:/Users/Administrator/Desktop/dangdangBookRank.csv'  
                url = 'http://bang.dangdang.com/books/bestsellers/01.00.00.00.00.00-24hours-0-0-1-'  
        
                for page in range(1, 26):  
                    des_url = url + str(page)  
                    html = getHTMLText(des_url)  
                    book_list = getBookInfo(html, book_list)  
                    print('正在爬取第' + str(page) + '页......')  
        
                saveCsvFile(path, book_list, fieldnames)

        在main()函数里,定义一个全局变量book_list,每次循环结果都保存在这个list里面,最后就得到了所有图书信息。再调用saveCsvFile()方法,就可以把数据保存在csv文件里。
        以下是完整代码:
        [python] view plain copy

            import requests  
            from bs4 import BeautifulSoup  
            import re  
            import csv  
        
            user_agent = 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)'  
            headers = {'User-Agent': user_agent}  
        
            # 获取指定网页的HTML内容  
            def getHTMLText(url):  
                try:  
                    r = requests.get(url, headers=headers)  
                    r.raise_for_status()  
                    r.encoding = r.apparent_encoding  
                    return r.text  
                except Exception as e:  
                    print(e)  
        
            # 获取图书信息  
            def getBookInfo(html, lst):  
                soup = BeautifulSoup(html, 'html.parser')  
                tag_ul = soup.find('ul', attrs={'class': 'bang_list clearfix bang_list_mode'})  
                tag_li = tag_ul.find_all('li')  
                for book in tag_li:  
                    book_info = {}  
        
                    book_rank = book.find('div', attrs={'class': re.compile('list_num$')})  
        
                    book_name = book.find('div', attrs={'class': 'name'}).a  
        
                    book_comments = book.find('div', attrs={'class': 'star'}).a  
        
                    book_author = book.find_all('div', attrs={'class': 'publisher_info'})[0].a  
                    # 24页第5本书的作者是直接在<div></div>标签内的,因此做一个辅助变量,在出现异常时顶替  
                    book_author_sup = book.find_all('div', attrs={'class': 'publisher_info'})[0]  
        
                    book_publish_date = book.find_all('div', attrs={'class': 'publisher_info'})[1].span  
        
                    book_publish_company = book.find_all('div', attrs={'class': 'publisher_info'})[1].a  
        
                    book_price = book.find('div', attrs={'class': 'price'}).span  
        
                    book_info.update({'排名': book_rank.get_text()[:-1]})  
                    book_info.update({'书名': book_name.get_text()})  
                    book_info.update({'评论数': book_comments.get_text()[:-3]})  
                    try:  
                        book_info.update({'作者': book_author.get_text()})  
                    except:  
                        book_info.update({'作者': book_author_sup.get_text()})  
                    book_info.update({'出版日期': book_publish_date.get_text()})  
                    book_info.update({'出版社': book_publish_company.get_text()})  
                    book_info.update({'售价': book_price.get_text()[-5:]})  
        
                    lst.append(book_info)  
        
                return lst  
        
            # 保存csv文件的函数  
            def saveCsvFile(path, lst, fieldnames):  
        
                # open函数注意两个问题:  
                # 1.'gbk'乱码问题:指定编码,加上encoding='utf-8'  
                # 2.写入的csv多空行问题:加上 newline=""  
                with open(path, 'w', encoding='utf-8', newline="") as file:  
                    dictWriter = csv.DictWriter(file, fieldnames)  
                    dictWriter.writeheader()  
                    dictWriter.writerows(lst)  
        
            def main():  
                book_list = []  
                fieldnames = ['排名', '书名', '作者', '评论数', '出版日期', '出版社', '售价']  
                path = 'C:/Users/Administrator/Desktop/dangdangBookRank.csv'  
                url = 'http://bang.dangdang.com/books/bestsellers/01.00.00.00.00.00-24hours-0-0-1-'  
        
                for page in range(1, 26):  
                    des_url = url + str(page)  
                    html = getHTMLText(des_url)  
                    book_list = getBookInfo(html, book_list)  
                    print('正在爬取第' + str(page) + '页......')  
        
                saveCsvFile(path, book_list, fieldnames)  
        
            main()  

        至此该爬虫完结,当然程序还有优化的地方,但功能实现了是首先的。这里用到的技术有:

        1.requests+BeautifulSoup根据节点爬取网页内容

        2.列表和字典的使用

        3.csv文件的写入操作
        看着自己的爬虫爬取了期望的数据当然是最开心的啦,继续加油~

      评论
      添加红包

      请填写红包祝福语或标题

      红包个数最小为10个

      红包金额最低5元

      当前余额3.43前往充值 >
      需支付:10.00
      成就一亿技术人!
      领取后你会自动成为博主和红包主的粉丝 规则
      hope_wisdom
      发出的红包
      实付
      使用余额支付
      点击重新获取
      扫码支付
      钱包余额 0

      抵扣说明:

      1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
      2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

      余额充值