自己写了一个爬虫爬取豆瓣小说,后来为了应对请求不到数据,增加了请求的头部信息headers,为了应对豆瓣服务器的反爬虫机制:防止请求频率过快而造成“403 forbidden”,乃至封禁本机ip的情况,而设置了代理ip,详细请见代码和注释。
爬取豆瓣小说的链接:https://www.douban.com/tag/%E5%B0%8F%E8%AF%B4/book?start=0
获取免费代理ip的网站:http://www.xicidaili.com/
1 #-*-coding:utf-8-*- 2 import urllib2 3 from bs4 import BeautifulSoup 4 import time 5 import random 6 7 class dbxs: 8 9 def __init__(self): 10 self.pageIndex = 0 11 self.enable = True 12 13 14 #获取html页面的内容 15 def getPage(self, pageIndex): 16 try: 17 #设置代理ip 18 enable_proxy = True 19 #Openers使用处理器Handlers,所有的“繁重”工作由Handlers处理,每个handlers知道如何通过特定协议打开URLs,或者如何处理URL打开时的各个方面 20 #在你使用代理上网或其他的情况就需要自己创建一个opener,可以实例化一个OpenerDirector,然后调用.add_handler(some_handler_instance) 21 #也可使用build_opener,这是一个更加方便的函数,用来创建opener对象,它只需要一次函数调用 22 proxy_handler = urllib2.ProxyHandler({'Http': '113.118.170.230:808'}) 23 null_proxy_handler = urllib2.ProxyHandler({}) 24 if enable_proxy: 25 #当你获取一个URL你要使用一个opener,默认情况下opener是urlopen,但urllib2.urlopen()不支持验证、cookie或者其他Http高级功能 26 #要支持这些功能,必须使用build_opener()创建自定义opener对象,build_opener([handler1 [handler2,...]]),参数handler是Handlers的实例,常用的有HTTPBasicAuthHandler、HTTPCookieProcessor、ProxyHandler 27 opener = urllib2.build_opener(proxy_handler) 28 else: 29 opener = urllib2.build_opener(null_proxy_handler) 30 urllib2.install_opener(opener) #install_opener用来创建(全局)默认opener,这个表示调用urlopen将使用你安装的opener 31 #获得页面响应的内容 32 url = 'https://www.douban.com/tag/%E5%B0%8F%E8%AF%B4/book' + "?start=" + str(pageIndex) 33 #设置请求头部信息,模拟浏览器的行为 34 my_headers = {'User-Agent':'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:55.0)'} 35 request = urllib2.Request(url, headers = my_headers) 36 response = urllib2.urlopen(request) 37 return response.read() 38 39 #另外一种随机设置请求头部信息的方法 40 #my_headers =['Mozilla/5.0 (Windows NT 6.1; WOW64; rv:55.0)', 'Mozilla/5.0 (Windows NT 6.1; Win64; x64)', 'Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0)'] 41 #header = random.choice(my_headers) #random.choice()可以从任何序列,比如list列表中,选取一个随机的元素返回,可以用于字符串、列表、元组 42 #request = urllib2.Request(url, headers = {'User-Agent': header}) 43 except urllib2.URLError, e: 44 if hasattr(e, "code"): 45 print e.code 46 if hasattr(e, "reason"): 47 print e.reason 48 return None 49 50 #过滤查找这一页的小说名字,信息和评分 51 def getContent(self, pageIndex): 52 pageCode = self.getPage(pageIndex) 53 soup = BeautifulSoup(pageCode, 'html.parser') 54 #在获得相应的内容中找出所有标签为<dd>的内容(里面包含了我们需要的小说信息) 55 contents = soup.find_all('dd') 56 #如果contents为真,能够获取到包含<dd>标签的内容,什么情况获取不到?我们发现豆瓣小说21页之后的所有页面里都不包含<dd>标签,我们应该停止打印 57 if contents: 58 #item为包含小说信息的每一页的内容 59 for item in contents: 60 title = item.find(class_ = 'title').string 61 info = item.find(class_ = 'desc').string.strip() 62 rate = item.find(class_ = 'rating_nums') 63 #通过试验,我们发现某一页可能存在小说没有评分,如果我们不判断rate,那么可能就出现报错 64 if rate: 65 rates = rate.string 66 print u"%s %s 评分:%s " %(title, info, rates) 67 #对于小说没有评分的内容,我们只打印小说名字,信息 68 else: 69 print u"%s %s " %(title, info) 70 #如果页面不包含<dd>标签,我们应该停止 71 else: 72 print u"所有页面已加载完" 73 self.enable = False 74 75 return contents 76 77 78 #创建一个开始方法 79 def start(self): 80 #打印第一页,此时self.pageIndex = 0,初始化时设置了 81 #设置页码x = 1 82 x = 1 83 #我们观察发现,第二页的pageIndex - 第一页的 = 第一页的小说的个数 84 #我们执行self.getContent的同时,获取了第一页的小说的个数 85 page_num = len(self.getContent(self.pageIndex)) 86 print u"第%s页" %x 87 88 #利用self.enable控制下一页的打印 89 while self.enable == True: 90 #设置下一页的pageIndex 91 self.pageIndex += page_num 92 #页码+1 93 x += 1 94 #time.sleep(1) #可以利用time模块来设置sleep时间 95 #再次调用self.getContent的同时,获取当前页的小说的个数 96 page_num = len(self.getContent(self.pageIndex)) 97 #在self.getContent中,如果不能获取到<dd>的内容,self.enable将会改为False,如果我们不加self.enable判断,仍会打印不存在小说信息的页码
if self.enable == True:
99 print u"第%s页" %x 100 101 102 DBXS = dbxs() 103 DBXS.start()