python爬虫之深度爬取实例

写了一个之前没完成的项目,代码优化不够,速度有点慢,应该也有错误的地方,望大佬看了之后能给点建议。。。。。。。。。

这是开始的url,先看一下它的网页结构:http://www.cymodel.net/deaafc/13143.html,可以观察到,整个网页大致分为六部分内容,中间的正文部分,右边的四部分新闻板块,还有最下面的一部分社会新闻。而每一个新闻链接点进去后又是一个相同模样的页面,爬取的目标是获取到所有的新闻title和对应的url。下面是代码,每部分链接的提取都差不多,利用find_all返回结果列表,然后再对列表进行遍历。

  1 import requests
  2 from bs4 import BeautifulSoup
  3 
  4 # response请求页面的响应,all_url_lis用于存放所有页面的utl,all_title_list用于存放所有页面的title,
  5 # i用来显示当前爬取到第几个页面
  6 
  7 
  8 def parse(response, all_url_list, all_title_list, i):
  9     html = response.content  # 先获取二进制形式的内容,下面再进行转换,否则会出现中文乱码
 10     html = str(html, encoding='utf-8')
 11     soup = BeautifulSoup(html, 'lxml')  # 利用Beautifulsoup解析库
 12     f = open('title_and_url.txt', 'a', encoding='utf-8')    # 打开文件,存储所有页面的title和url
 13 
 14     # 获取正文
 15     # content = soup.find(name='div', attrs={'class': 'main_article'})
 16     # p_list = content.find_all(name='p')
 17     # for p in p_list:
 18     #     print(p.string)
 19 
 20     flag = 0    # 用来标志当前页面的url有多少已经存储过了,后面可以作为结束循环的条件
 21 
 22     # 获取下方社会新闻
 23     Sociology_list = soup.find_all(name='div', attrs={'class': 'r'})
 24     sociology_a_list = Sociology_list[0].find_all(name='a')
 25     for a in sociology_a_list:
 26         sociology_title = a.string
 27         sociology_url = a.attrs.get('href')
 28         # print(sociology_title, sociology_url)
 29         # 判断列表中是否已经存在这个页面的url或title,实现去重
 30         if sociology_url not in all_url_list and sociology_title not in all_title_list:
 31             all_url_list.append(sociology_url)
 32             all_title_list.append(sociology_title)
 33             f.write(sociology_title + '   ' + sociology_url + '\n')
 34         else:
 35             flag += 1
 36 
 37     # 获取排行榜
 38     Ranking_list = soup.find_all(name='ul', attrs={'class': 'tt', 'id': 'tt'})
 39     rank_a_list = Ranking_list[0].find_all(name='a')
 40     for a in rank_a_list:
 41         rank_title = a.string
 42         rank_url = a.attrs.get('href')
 43         # print(rank_title, rank_url)
 44         if rank_url not in all_url_list and rank_title not in all_title_list:
 45             all_url_list.append(rank_url)
 46             all_title_list.append(rank_title)
 47             f.write(rank_title + '   ' + rank_url + '\n')
 48         else:
 49             flag += 1
 50 
 51     # 热点推荐
 52     hot_list = soup.find_all(name='ul', attrs={'class': 'ducheng_list'})
 53     hot_a_list = hot_list[0].find_all(name='a')
 54     for a in hot_a_list:
 55         hot_title = a.string
 56         hot_url = a.attrs.get('href')
 57         # print(hot_title, hot_url)
 58         if hot_url not in all_url_list and hot_title not in all_title_list:
 59             all_url_list.append(hot_url)
 60             all_title_list.append(hot_title)
 61             f.write(hot_title + '   ' + hot_url + '\n')
 62         else:
 63             flag += 1
 64 
 65     # 热点视频
 66     video_list = soup.find_all(name='ul', attrs={'class': 'tuku_list'})
 67     video_a_list = video_list[0].find_all(name='a')
 68     for a in video_a_list:
 69         video_title = a.string
 70         video_url = a.attrs.get('href')
 71         # print(video_title, video_url)
 72         if video_url not in all_url_list and video_title not in all_title_list:
 73             all_url_list.append(video_url)
 74             all_title_list.append(video_title)
 75             f.write(video_title + '   ' + video_url + '\n')
 76         else:
 77             flag += 1
 78 
 79     # 要闻
 80     yaowen_list = soup.find_all(name='ul', attrs={'class': 'yaowen_list'})
 81     yaowen_a_list = yaowen_list[0].find_all(name='a')
 82     for a in yaowen_a_list:
 83         yaowen_title = a.string
 84         yaowen_url = a.attrs.get('href')
 85         # print(yaowen_title, yaowen_url)
 86         if yaowen_url not in all_url_list and yaowen_title not in all_title_list:
 87             all_url_list.append(yaowen_url)
 88             all_title_list.append(yaowen_title)
 89             f.write(yaowen_title + '   ' + yaowen_url + '\n')
 90         else:
 91             flag += 1
 92 
 93     f.close()
 94     print('第{0}个页面存储完成'.format(i), flag)
 95     # 一个页面中有44条新闻。如果改页面中的所有url都已经被存储过了,则可以大致认为已经获取到了所有的url
 96     # 实际少了十三条
 97     if flag == 44:
 98         return flag
 99     else:
100         return
101 
102 
103 if __name__ == '__main__':
104     all_url_list = []
105     all_title_list = []
106     url = 'http://www.cymodel.net/deaafc/13143.html'
107     all_url_list.append(url)
108     i = 0
109     while (True):
110         # 如果想要把all_url_list里面的每个页面的url全部爬取一遍,则可以用这个条件作为循环结束
111         # 把下面的内嵌if和函数里面的if else注释掉即可
112         if( i < len(all_url_list) ):
113             response = requests.get(url=all_url_list[i])
114             flag = parse(response, all_url_list, all_title_list, i+1)
115             i += 1
116             if flag == 44:
117                 print('已爬取大部分的url!!!!!')
118                 break
119         else:
120             print('已爬取到所有的url!!!!!')
121             break

再写的时候,主要遇到了两个问题,一是如何实现去重,二是爬取到什么时候结束。

第一个问题的解决办法是,先定义两个列表,用于存放每个页面的url和title,也就是all_url_liat和all_title_list,然后再每次存放url和title之前,先判断列表里面有没有这个url,如果没有,则进行存储,并添加到列表中。本来之定义了一个url的列表,但后来发现有的网页之间url不同,title相同,里面的内容也相同,所以又加了一个all_title_list。用这种方法实现去重的好处是比较简单,容易想到,但坏处是列表里面的元素过多,比较占内容,会有两个具有四百多个元素的列表,而且每次添加数据前,都要过一遍列表,判断要添加的url是否已经再列表中,这样就会导致程序运行较慢。

第二个问题的解决办法一是根据每个页面未被存储的url数量判断,每个页面中共有44个新闻的链接,如果改页面中的44个链接都已经被存储过了,那么就认为已经获取到了大部分的url,第二种办法是把all_url_list中的每个url都爬取一下,这样能获取到所有的新闻链接,但耗时有点长,代码还需要优化。第一种办法的获取结果为416条,第二种办法获取到的是429条。

*****************************不积跬步,无以至千里。 *****************************