Python爬虫

云计算 waitig 533℃ 百度已收录 0评论

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

在前两次的爬虫编写过程中,思想都是把整个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文件的写入操作
      看着自己的爬虫爬取了期望的数据当然是最开心的啦,继续加油~


      本文由【waitig】发表在等英博客
      本文固定链接:Python爬虫
      欢迎关注本站官方公众号,每日都有干货分享!
      等英博客官方公众号
      点赞 (0)分享 (0)