基于Requests的Python爬虫入门实例------爬取豆瓣图书排行榜的前25本图书(小白福利)

 话不多说,先上代码: 

# -*- coding:utf-8 -*-
import sys
import requests
import lxml
from bs4 import BeautifulSoup
from requests.cookies import RequestsCookieJar


#设置请求头,伪装成浏览器
headers = {'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.108 Safari/537.36'}


#设置目标url
url = 'https://book.douban.com/top250?start=0'


#使用requests模块提供的的Http服务
resp = requests.get(url, headers = headers)


#如果目标网页编码与本地不一致,修改本地默认编码方式(防止输出中文乱码)
if sys.getdefaultencoding() != resp.encoding:
    reload(sys)
    sys.setdefaultencoding(resp.encoding)


#使用BeautifulSoup来分析和定位Html中我们所需的内容
soup = BeautifulSoup(resp.text,'lxml')              #构建BeautifulSoup对象


#创建记录数据的文件
file_out = "C:\\out.txt"            #Windows下文件名分隔符为  " \\ " 

i = 0

#使用BeautifulSoup中的select方法(返回的是list对象)获取所需内容

name_list = soup.select('tr > td > div.pl2 > a')    #设置select方法中的参数可以用XPath也可以直接通过标签结点层层递进

#定义一个结果列表

result_list  = ["豆瓣图书排行榜"]

#定义一个查重并更新列表的方法,如果当前元素已存在于列表中则不做更新操作
def FindIfRepeat (OldList,item):
    if item not in OldList:
        NewList = OldList.append(item)
        return NewList
    else:
        return OldList

#用for循环遍历soup对象返回的列表

for name in name_list:
    i += 1
    outcomeList = name.get_text().strip().split()        #对于返回的结果进行分段并去掉两端空格
    for outcome in outcomeList:
        m = len(outcomeList)
        if m >= 2 :                                      #判断是否有对书的描述字段

            #使用迭代器遍历outcomelist
            Newoutcome = ""
            it = iter (outcomeList)
            for x in it:
                Newoutcome = Newoutcome + str(x) + " "
            Newoutcome = Newoutcome.split(':',1)
            #对于获取的结果做格式化处理
            name_format = "Top{rank},书名《{name}》,描述:{description}".format(rank = str(i),name = Newoutcome[0],description=Newoutcome[1])
            FindIfRepeat(result_list,name_format)         #调用查重函数进行查重更新结果列表的操作
        else:
            name_format = "Top{rank},书名《{name}》,描述:暂无".format(rank = str(i),name = outcomeList[0])
            FindIfRepeat(result_list,name_format)

#将结果写入文件中
for i in range(len(result_list)):
    with open (file_out , "a+" ) as f :#使用with...open格式打开文件的好处在于不用手动关闭文件
        f.write(str(result_list[i]) + '\r\n')



  输出结果:

豆瓣图书排行榜

Top1,书名《追风筝的人》,描述:暂无

Top2,书名《解忧杂货店》,描述:暂无

Top3,书名《小王子》,描述:暂无

Top4,书名《白夜行》,描述:暂无

Top5,书名《围城》,描述:暂无

Top6,书名《三体 》,描述: “地球往事”三部曲之一 

Top7,书名《嫌疑人X的献身》,描述:暂无

Top8,书名《活着》,描述:暂无

Top9,书名《挪威的森林》,描述:暂无

Top10,书名《百年孤独》,描述:暂无

Top11,书名《红楼梦》,描述:暂无

Top12,书名《看见》,描述:暂无

Top13,书名《平凡的世界(全三部)》,描述:暂无

Top14,书名《三体Ⅱ 》,描述: 黑暗森林 

Top15,书名《三体Ⅲ 》,描述: 死神永生 

Top16,书名《不能承受的生命之轻》,描述:暂无

Top17,书名《达·芬奇密码》,描述:暂无

Top18,书名《我们仨》,描述:暂无

Top19,书名《天才在左 疯子在右 》,描述: 国内第一本精神病人访谈手记 

Top20,书名《简爱(英文全本)》,描述:暂无

Top21,书名《哈利·波特与魔法石》,描述:暂无

Top22,书名《明朝那些事儿(壹) 》,描述: 洪武大帝 

Top23,书名《傲慢与偏见》,描述:暂无

Top24,书名《目送》,描述:暂无

Top25,书名《恶意》,描述:暂无

不知道你们看懂了没,如果你是小白,那就请你往下看代码详解,大佬请绕道,哈哈!

代码详解

首先:你得知道一个制作一个爬虫的大概流程如下:

获取目标URL→通过requests(也可以使用urllib)等模块建立HTTP连接获得网页的返回内容➡通过BeautifulSoup(或者lxml)等模块解析HTML文档寻找所需内容➡遍历BeautifulSoup对象,输出目标内容到控制台或者指定文件。

准备工作:导入相关库和设置编码方式(很重要,爬虫最常见错误就是抓取回来的内容乱码,好习惯很重要哦!)

# -*- coding:utf-8 -*-
import sys
import requests
import lxml
from bs4 import BeautifulSoup
from requests.cookies import RequestsCookieJar

设置请求头,将爬虫伪装成浏览器(有些网站设置了反爬机制,不设置这个有可能爬虫没法用)

#设置请求头,伪装成浏览器
headers = {'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.108 Safari/537.36'}

设置请求头方法参考:https://blog.csdn.net/FloatDreamed/article/details/79208719

设置URL和创建requests对象

#设置目标url
url = 'https://book.douban.com/top250?start=0'


#使用requests模块提供的的Http服务
resp = requests.get(url, headers = headers)

URL很简单,就是要爬取的目标网页。

创建requests对象,URL参数是必须的,其他的headers以及待会儿会讲到的cookie和proxies(代理)是可选的。有了requests对象,就可以使用它的Get 和Post方法了,如果学过Java,就应该明白这两个功能对于日常的网络服务是完全够用了的 

Get方法用于向服务器请求并得到从服务器返回的数据(response对象),Post方法用于提交表单,向服务器更新数据等操作。

 Requests库的详细用法参考:https://blog.csdn.net/iloveyin/article/details/21444613

中文乱码的解决方法

前面提到了爬虫最常见的问题是返回的数据中文乱码,对于爬虫小白来说这样的问题几乎不可避免,不过别担心,我这里有好几种解决中文乱码的方法,总有一款适合你。

方法一:(适用于Pycharm下编程)

先在代码头设置编码方式为 " UTF-8" ,UTF-8 是保存中文字符的通用代码。然后,如图所示的操作一般都能解决中文乱码问题。

 其他方法参考以下链接:

https://blog.csdn.net/weixin_42134789/article/details/82904741

 使用BeautifulSoup解析HTML文档

#使用BeautifulSoup来分析和定位Html中我们所需的内容
soup = BeautifulSoup(resp.text,'lxml')              #构建BeautifulSoup对象

#使用BeautifulSoup中的select方法(返回的是list对象)获取所需内容

name_list = soup.select('tr > td > div.pl2 > a')    #设置select方法中的参数可以用XPath也可以直接通过标签结点层层递进

 写爬虫程序最关键的部分在于如何从网页中提取我们想要的内容,这里用到了一个强大的HTML解析库-----BeautifulSoup,通过BeautifulSoup对象可以很轻松的通过select或是find_all方法从繁杂的HTML中提取到有用的信息,其中最难理解的应该是select等方法中的参数怎么获取,不着急,下面就手把手的教你:

以下全程使用chrome浏览器,其他浏览器的操作步骤类似:

第一步:使用浏览器打开目标网页,F12进入开发者模式

第二步:点击图中所示按钮,再点击所需要定位的内容

 第三步:分析复制下来的位置信息

#content > div > div.article > div > table:nth-child(2) > tbody > tr > td:nth-child(2) > div.pl2 > a

其实这看似复杂的东西不过就是HTML文档中书名标题所在的位置,是一层层的标签嵌套关系,我们的select方法就是要靠这个参数来定位到HTML文档中书名标题所在位置,然后通过soup.text 把书名标题标签里的内容提取出来,然后再输出到控制台或者写入文件中,我们爬虫的作用就达到了。

 当然,复制过来的东西还不能直接用,因为这只是一个标题的,而我们要的是TOP25,所以要把具体的部分去掉,可以同样的方法多定位几个标题,多对比几次,找出共同的部分。

#一开始拿到的《追风筝的人》的定位是
#content > div > div.article > div > table:nth-child(2) > tbody > tr > td:nth-child(2) > div.pl2 > a


#这是图中《解忧杂货店》的定位
#content > div > div.article > div > table:nth-child(4) > tbody > tr > td:nth-child(2) > div.pl2 > a


#这是中《小王子》的定位
#content > div > div.article > div > table:nth-child(6) > tbody > tr > td:nth-child(2) > div.pl2 > a

 把变化的地方去掉,留下共同的部分,tr前面都一样,累赘删掉了(后面有个div.p12是整个HTML中唯一,前面的父标签就可以省去了。)

简化后的结果如下:

> tr > td:nth-child(2) > div.pl2 > a

#进一步简化

> tr > td > div.pl2 > a

这里的分析只是一个参考,select中还可以填入其他的参数,像是正则表达式什么的,也可以使用find_all方法寻找内容,有关BeautifulSoup的详细使用方法可以参考:https://blog.csdn.net/qq_21933615/article/details/81171951

解析HTML文档的这部分内容是爬虫的核心,这些定位参数决定爬虫能否爬取到所需信息,一定要细心呐!

 剩下的代码就是常规的东西了,是根据前面具体的返回结果的格式来设计如何美化输出,可以先把爬回来的东西输出到控制台,看看效果,然后再做相应的调整。

#把返回的内容先输入到控制台看看效果
for name in name_list:
    i += 1
    print(i,name.get_text().strip())

 控制台显示的效果如下:

 还行,中间有一大段空格,可以用str.format()函数进行格式化输出

#用for循环遍历soup对象返回的列表

for name in name_list:
    i += 1
    outcomeList = name.get_text().strip().split()        #对于返回的结果进行分段并去掉两端空格
    for outcome in outcomeList:
        m = len(outcomeList)
        if m >= 2 :                                      #判断是否有对书的描述字段

            #使用迭代器遍历outcomelist
            Newoutcome = ""
            it = iter (outcomeList)
            for x in it:
                Newoutcome = Newoutcome + str(x) + " "
            Newoutcome = Newoutcome.split(':',1)
            #对于获取的结果做格式化处理
            name_format = "Top{rank},书名《{name}》,描述:{description}".format(rank = str(i),name = Newoutcome[0],description=Newoutcome[1])
            FindIfRepeat(result_list,name_format)         #调用查重函数进行查重更新结果列表的操作
        else:
            name_format = "Top{rank},书名《{name}》,描述:暂无".format(rank = str(i),name = outcomeList[0])
            FindIfRepeat(result_list,name_format)

#将结果写入文件中
for i in range(len(result_list)):
    with open (file_out , "a+" ) as f :#使用with...open格式打开文件的好处在于不用手动关闭文件
        f.write(str(result_list[i]) + '\r\n')

 美化之后的效果:

 哈哈,强迫症的我看着就舒服多了。。。

知识拓展

 

  1. 使用proxies代理

前面提到了,有些网站会有反爬机制,要是一不小心被封了IP,那多尴尬呀!不慌,这篇博客就是给小白们提供福利的,下面就是使用代理的方法。

#使用动态代理,防止被封IP
proxies = {
    "http": "http://149.129.70.226:8434",
    "https": "http://218.28.238.165:8267",
}

#使用requests模块提供的的Http服务
resp = requests.get(url, headers = headers,proxies = proxies)

使用动态代理其实至于要定义一个参数proxies,然后把IP加进去,再加到requests请求方法中就行了鸭!easy?

不不不不不,其实你在使用的时候可能会碰到各种连接不上的情况,比如下面这种:

 看吧,没这么简单吧?其实这是因为我这里用的IP地址是网上找到的免费IP,用的人多了,被目标网站封掉了(呜呜呜~),所以爬虫还是有风险的哦,不要轻易用自己的电脑IP反复爬取同一个网站哦!网上的免费IP很多,可以参考这个网址http://www.data5u.com/上面有10个免费IP可以用,不定期更新,一个不行就试试另一个呗~

最后提醒一点:爬取https的网站就要用HTTPS的IP哦!不然还是可能会连不上~

2.在请求头中加入cookie或者使用session保持登陆

有时候爬取某些网站的时候需要先登录,但是呢,我们爬取数据的时候不可能每爬取一次就重新登录一次,那样就太繁琐了,所以就要用到cookie(小甜饼),这可是浏览器最爱的美食呢!里面记录了用户的登录信息,我们只需要把它加到我们的请求头里就不用每次都登录啦!因为这相当于告诉服务器,“ 对,我胡汉三又回来啦!" ,服务器可以通过cookie知道当前请求的客户端已经登录过了。

#方法一

#首次使用cookie时可以先打印出浏览器中保存的cookie格式,然后再设置相应的cookie
resp = request.get(url,headers = headers)
print(resp.cookies)

#设置cookie(保存在本地端的用户信息)
 cookie_jar = RequestsCookieJar()        #创建一个cookiejar对象,urllib中也有类似的东西,作用是生成一个cookie对象
 cookie_jar.set(name  = " root " ,password =" 123456 " ) #set方法设置cookie的具体内容

 response = requests.get("url", cookies=cookie_jar)


#方法二

#使用session(会话)维持登陆(相当于保存在服务器端的cookie)
 session1 =requests.session()              #创建session对象
 resp = session1.get("url",headers = headers)    #再用session对象进行HTTP请求,这样就可以维持登录状态

#方法一和二 只用一种就行

—————————————————————————   END ————————————————————————————

  • 5
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

daimashiren

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值