【Python网络爬虫】使用requests和beautifulsoup4库轻松实现

如何用Python编写网络爬虫?

python提供了很方便的库来帮助我们实现很多复杂的功能。在编写网络爬虫的过程中,我们可以使用requests来与网站交互并获取网页的源代码,再使用beautifulsoup4对得到的网站源代码(通常是html)进行处理来获取所需要的内容。下面进行详细的介绍。

关于网页的基础知识

urlUniform Resource Locator)也就是我们平时所说的域名,也就是网址。当用户在浏览器中输入网址后,浏览器会先访问本地的hosts文件来寻找是否存在匹配的IP地址,如果没有找到则再通过DNS服务器去获得正确的IP地址进行访问。例如域名www.baidu.com的IP地址为14.215.177.39。

对于一个网页,在浏览器上右键->查看源代码即可查看该网页的实现。网页的源代码大多都是以<p attribute>text</p>的html格式,其中成对的p称为标签, 标签后面的键值对称为属性, 标签对之间的部分称为正文。不同的标签显示出来的功能和效果截然不同。我们需要做的就是在这些标签里获取我们需要的信息。

给服务器传送数据有多种方式。

1.最简单的就是get方式,在域名后面加上?attr : a=a1&b=b1...x=x1,相当于一个{a:a1,b:b1,c:c1...x:x1}的参数表。

2.稍复杂一些的是post方式传值,像密码这样的需要藏起来的数据自然不能采用明文的get,还有像填一些表格,数据量比较大的也往往采用post方式传值。

关于requests库

requests库可用于访问网页,上传数据等操作。

http://docs.python-requests.org/en/master/

这是requests库的文档,写的很详细。这里我们就简要介绍一些常见的简单用法。

r = request.get(url) 

这样我们就有了一个名为r的 Response对象,通过r.text就可以查看url网页的源代码。

最简单爬虫直接对r.text进行处理就可以获得我们想要的内容。处理的方式有很多种,最简洁的处理方式是采用正则表达式处理,(关于正则表达式的更多内容可以看我之前的博客)比如说我们需要爬取图片,而源代码中图片的url以

"ObjURL":"http:\/\/img3.imgtn.bdimg.com\/it\/u=560465708,1507159867&fm=214&gp=0.jpg"
形式出现,那我们可以采用for x in re.findall(pt , r.text)的方式遍历所需要的图片的url。

其中pt是可与上面html匹配的正则表达式,例如pt = '\"objURL\":\"((http://|https://)[^\"]*)\"'。

session_requests = requests.session()
在浏览器同时访问同一个网站时,之前已经上传过的信息往往不必重复上传,比如往往登陆过一次过后就可以始终在登陆状态下浏览。这是通过cookies实现的,就相当于浏览器存储了一部分信息,这样每次访问cookies在浏览器和服务器之间传输,省去了人需要重复发送信息的麻烦。更多关于cookies可以查看https://zh.wikipedia.org/wiki/Cookie。

在requests中我们就可以通过session来实现这一功能,封装好的session模块很好用也很方便。

比如类似以下代码,就可以向服务器发送post请求,其中data就是我们需要传送的数据。

 result = session_requests.post(  # 向服务器发送post请求
        url,
        data=mylog,
        headers=dict(referer=url),
    )

假设某个网站需要登陆操作,那么怎么爬取登陆过后网页的信息呢?我们就可以使用session模块的post方法,现在问题来了,我们在登陆页面输入了用户名和密码,点击登陆后到底传输了哪些数据呢?只有知道了数据的格式,我们才能进行模拟传输。

我们可以通过下载一个叫Fiddle4的免费软件来实现,Fiddle4会截取浏览器post的内容,因此我们通过这种方式查看login所使用的url和data。

以openjudge为例,当我们login后,在Fiddle4中可以发现data就是

mylog = {"redirectUrl": "http://openjudge.cn/",
         "password": "",
         "email": ""}
的格式。


关于beautifulsoup4库

请查看官方文档:https://www.crummy.com/software/BeautifulSoup/bs4/doc/index.zh.html

好好看看findall就够用了,find的使用和findall几乎相同。参数有多种写法,甚至可以带判别函数和正则表达式的形式,强烈建议看文档!

for tag in find_all( name , attrs , recursive , text , **kwargs )

返回值是beautifulsoup的类的列表。

它可以通过tag["attr"]来访问和修改属性(类似python里的dict),可以通过tag.text访问正文。如果没有符合要求的tag则返回空列表。

find的参数表与findall相同,只是返回值是一个单独的beautifulsoup类或者None

有时间再更...

以下是用python实现的登陆openjudge,并且爬取accept代码的程序
import requests
import bs4
import re
code_class = {"sh_cpp": ".cpp",
              "sh_c": ".c", "": ".py",
              "sh_pascal": ".pas",
              "sh_java": ".java"}
mylog = {"redirectUrl": "http://openjudge.cn/",
         "password": "",
         "email": ""}
session_requests = requests.session()
own_url = "http://openjudge.cn/"

#爬取个人主页url下accept的内容,若有next page则继续爬取
def download_url(url):
    global session_requests
    global own_url
    global code_class
    ans = session_requests.get(url)
    s = str(ans.content, encoding="utf-8")
    soup = bs4.BeautifulSoup(s, "html.parser")
    blocks = soup.find_all("a", class_="result-right")
    #blocks包含accept代码网页的信息,遍历该页
    if blocks != []:
        for i in blocks:
            solution_url = i["href"]
            solution = session_requests.get(solution_url)
            ss = str(solution.content, encoding="utf-8")
            s_soup = bs4.BeautifulSoup(ss, "html.parser")
            #判断该题的代码类型
            for class_name in code_class:
                block = s_soup.find("pre", class_=class_name)
                if block == None:
                    continue
                try:
                    name = s_soup.find_all("h3")[1]
                    name = name.text[:-5]
                except:
                    print("Get name wrong!")
                #去掉第一个':'前面的编号
                index = name.find(':')
                if (index != -1):
                    name = name[index + 1:]
                #去除题名中的非法字符和开头结尾的空格
                name = re.sub(r"[\\/:*?#\"<>|:]", " ", name).strip()
                try:
                    #已存在同名代码
                    f = open("C:/tmp/" + name + code_class[class_name])
                    print(name + " has already downloaded")
                    continue
                except IOError:
                    #不存在同名代码
                    print("downloading your correct code " + name)
                    try:
                        f = open("C:/tmp/" + name + code_class[class_name], 'w', encoding = "utf-8")
                        new_str = block.text
                        f.write(new_str)
                        f.close()
                    except Exception as e:
                        print(name + " can't be downloaded correctly")
                        print(e)
    # next 是下一页的相对路径
    next = soup.find("a", class_="nextprev", rel="next")
    if next != None:
        download_url(own_url + next["href"])

def spider():
    global code_class
    global mylog, session_requests, own_url
    mylog["email"] = input("请输入您登陆openjudge使用的email账号:\n")
    mylog["password"] = input("请输入您的密码:\n")
    login_url = "http://openjudge.cn/api/auth/login/"
    result = session_requests.post(  # 向服务器发送post请求
        login_url,
        data=mylog,
        headers=dict(referer=login_url),
    )
    result = session_requests.get("http://openjudge.cn/")
    #用正则表达式匹配寻找个人首页的url
    pt = r"<a href=\"(http://[^\"]*)\">个人首页</a>"
    try:
        own_url = re.search(pt, result.text).group(1)
        print("这是您的主页:" + own_url)
    except:
        print("账号不存在或密码错误!请重新输入!")
        spider()
        return
        own_url = ''
    download_url(own_url)
    print("您已成功下载所有accept的程序至c:\\tmp文件夹下!")
    
spider()

猜你喜欢

转载自blog.csdn.net/weixin_40841416/article/details/80293393