其他测试框架 Python 网络爬虫 (二)

刘津嘉 · 2016年04月14日 · 最后由 54dmx 回复于 2019年02月15日 · 35 次阅读

title: Python 网络爬虫 (二)
date: 2016-04-13 12:47:44

tags: Python

< Hi , 大家好,我是 Raymond 。 应广大同学要求, 今天加更一波。 有没有 surprise ! >

承接上一章 ,回顾一下上节内容

练习一:

获取任意 TesterHome 的文章 (这里用上一章的 url 地址)

import requests     # 导入requests模块

request_url = 'https://testerhome.com/topics/4621'  # 请求的url是 上一章的url地址
response = requests.get(request_url).text # 请求并返回结果
print(response)     # 打印返回结果

如果你熟练掌握了这一步, 那么,我想如果没有一些 python 爬虫基础的话, 爬取知乎的时候,我猜你肯定遇到困难了。
别着急,我们来简单的学习一些 html 的解析, 从而完成知乎的爬取吧。

BeautifulSoup4 模块

Beautiful Soup 是一个可以从 HTML 或 XML 文件中提取数据的 Python 库.它能够通过你喜欢的转换器实现惯用的文档导航,查找,修改文档的方式.Beautiful Soup 会帮你节省数小时甚至数天的工作时间.

传送门 :BeautifulSoup4

这个模块的主要作用,是将我们抓取回来的 html 解析之后,提取出有效的数据进行存储。

Python Re 模块

正则表达式(RE)模块的功能主要是设置一个字符串并搜索其中的字串;这个模块的功能让你检查一个特定的字符串,匹配给定的正则表达式(或正则表达式匹配特定的字符串,它可以归结为对同样的事情,一般情况下,NFA 引擎是由表达式主导,而 python 的 re 正是 NFA 引擎,从引擎的机制上来描述,应该是理解为拿正则表达式匹配特定的字符串;DNF 引擎反之,详细可参考精通正则表达式一书关于正则引擎的章节)。

传送门 :Python Re

我们在这里不对 Re 和 BeautifulSoup 这两个模块进行比较 , 我们先从最简单的 BeautifulSoup 的 Html 解析开始

第一次使用 BeautifulSoup4

我相信大家在看 Bs4 的中文文档的时候, 也上手进行了编码 ,那么,快点开始吧!

首先! ,我们将昨天的代码拿出来改一下

import requests     # 导入requests模块
from bs4 import BeautifulSoup as bs # 从bs4 模块中导入BeautifulSoup模块并命名为bs

request_url = 'https://testerhome.com/topics/4621'  # 请求的url是 上一章的url地址
response = bs(requests.get(request_url).text , 'lxml') # 返回一个bs对象 ,格式为lxml
print(response)     # 打印返回结果

好的, 我们成功的接受到返回的页面,现在这个返回的对象, 类型是 bs 对象的类型,我们对返回的 html 进行解析

import requests     # 导入requests模块
from bs4 import BeautifulSoup as bs # 从bs4 模块中导入BeautifulSoup模块并命名为bs

request_url = 'https://testerhome.com/topics/4621'  # 请求的url是 上一章的url地址
response = bs(requests.get(request_url).text , 'lxml') # 返回一个bs对象 ,格式为lxml
print("这篇文章的名字是 :" , response.h1.string)  # 获取文章标题˜
print("该文章属于 :" , response.find('a',{"class":"node"}).text) #获取发表在哪一个技术类型下
print("该文章的分类为 : ", response.h2.string)
print("-------"*10+"这里是获取所有的楼层评论"+"-------"*10)
for i in response.find_all('div',{"class":"reply"}):
    print(i.p.text)
print("-------"*10+"这里是获取所有的楼层评论"+"-------"*10)

# 见证奇迹的时刻到了!

运行一下代码,看看结果如何!

这篇文章的名字是 : Python 网络爬虫 (一)
该文章属于 : 其他测试框架
该文章的分类为 : tags: Python
----------------------------------------------------------------------这里是获取所有的楼层评论----------------------------------------------------------------------
是准备用 urllib 还是直接用 scrapy 啊
#1 楼 @jphtmt 不用框架, 自己写轮子,后续讲分布式,这部分其实主要的用意是让大家写出 pythinic 的代码 , 熟悉并习惯 python 的代码形式
#2 楼 @raymond 那解析呢,用 bs4?这些天一直在尝试写一个爬虫,卡在验证码了
#3 楼 @jphtmt 验证码部分现在通常的做法是将验证码拉回本地,手动输入,如果你想程序自动识别图像,这个太困难了
#4 楼 @raymond 我就是拉回本地的, 但是手动输入后就出了问题
#5 楼 @jphtmt 可否发给我看一下
#6 楼 @raymond 代码还在远程服务器上,得回去找找,希望能写个处理验证码的例子,嘿嘿
#7 楼 @jphtmt 下一章会放两部分的爬虫内容, 一个是 html 的简单解析,第二部分,是应用的模拟登录, 你说的内容, 可能会在第三章中放出来, 结合第二章的内容, 用 python 实现登陆 TesterHome
#8 楼 @raymond 好,我之前尝试的是豆瓣,我找时间尝试下登录 testerhome 试试
感谢楼主的技术分享,小白第一步就卡住了,py2.7 并不包含这些模块,可否另开一个传送门引导?
#10 楼 @jamesparagon pip 大法
#9 楼 @jphtmt TesterHome 的登陆, 有_xsrf 验证 包含了 bs4 的解析模块还有你提到的验证码
#12 楼 @raymond 嗯, 我看到了,知乎也采用了 xsrf 验证,每次抓取 xsrf 值就好了吧
#10 楼 @jamesparagon requests 需要安装,pip 一下吧
#13 楼 @jphtmt 对 每次登陆获取一次就好了。前两天我还在群里说。。TesterHome 的登陆验证方式,和知乎很相似啊
成功了,不过小白作死尝试了一下 www.baidu.com 电脑直接蓝屏了
给煎饼怂恿下这么快就出来了,把一系列的都写出来吧,看样子不错
#17 楼 @darker50 哈哈, 好的, 得向煎饼多学习 , 这套系列 预计是分 5 章写完, 初级的 python 爬虫造轮子系列
zan
你这文章这么短, 差评啊.
#20 楼 @seveniruby 不短点留点神秘,怎么拉起人的好奇心呢
#21 楼 @raymond 作业已完成 期待老师的新课
#17 楼 @darker50 哈哈,幸福
坐等连载~
#24 楼 @jianjianjianbing 嘿嘿。这部分还是比较简单的,后面如果大家都感兴趣,再开一片多线程消息队列的
#23 楼 @jianjianjianbing 下次看你分享,你懂的好像更多。
已关注大神,默默等待更新
期待更新,一直想尝试爬虫
慕课网有 nodejs 写的爬虫
期待后续内容

----------------------------------------------------------------------这里是获取所有的楼层评论----------------------------------------------------------------------

既然我们已经了解 Bs 模块, 那么大家或许在昨天的练习中发现,获取知乎的文章,好像需要登陆啊?可是。。我们如何登陆呢? -- 这是一个问题啊!

通过 Python 进行一次简单的登陆行为

话不多说, 上代码

import json
import requests
#这是基于闪送app的api实现的模拟登陆

def login():
    get_cookies = 'http://www.ishansong.com/web/admin/order/list'
    r = requests.get(get_cookies)
    cookies = r.cookies
    headers = {
        "Host":"www.ishansong.com",
        "Origin":"http://www.ishansong.com",
        "Referer":"http://www.ishansong.com/user/login",
        }

    url = 'http://www.ishansong.com/user/doLogin'
    data = {"service":"","tab":"tab2","username":xxxx,"password":xxxx}#注册后,在这里把username、password的参数修改成自己的用户名和密码即可

    r = requests.post(url ,data = data ,headers = headers , cookies = cookies )
    print (r.text)

if __name__ =='__main__':
    login()

根据我们上一章所讲,在 requests 模块中用到 post 方法,并实现登陆完成 ,大家需要多练习。

那大家肯定问我,为什么会知道登陆成功了呢?

很简单啊 你用 Bs4 模块解析一下这个返回的 html 看看是不是成功了呢 ?

留下一些练习:

  • 使用 bs4 对闪送 app 进行解析
  • 尝试使用 requests 方法 获取一张图片 (可以但不限于,把图片保存在本地)

那么今天我们分享的内容就到这里啦
希望大家多多练习!

再进行代码编写的时候,如果遇到问题,要及时查看官方 Api 以及 Google ,这里我们就不对模块的使用进行深入解析了,如遇到问题 可在 TesterHome 官方测试群中 @BJ-行者

如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
共收到 40 条回复 时间 点赞

最好能再细一点,登录的具体实现流程,
1. 登录的流程介绍
2. 登录的信息获取,host,Referer 等信息如何抓取(fiddler 使用介绍)
3. requests 的 API 链接,介绍下

原来是行者呀…我说呢

什么时候讲知乎的登录流程?

#1 楼 @carl requests 链接在第一章有贴。

#3 楼 @cano 下一章讲验证码获取,如果没有意外,知乎应该在第四章

#2 楼 @lylyliuyu

说的不好,海涵

#3 楼 @cano 师傅您老人家来了

#6 楼 @raymond 我旧电脑用的是 py2.7 拷贝上面的代码反馈的是:是模块的问题么?明天我再试试其他的机器
Traceback (most recent call last):
File "C:\Python27\Hello world.py", line 6, in
response = bs(requests.get(request_url).text , 'lxml') # 返回一个 bs 对象 ,格式为 lxml
File "C:\Python27\lib\site-packages\bs4_init.py", line 156, in __init_
% ",".join(features))
FeatureNotFound: Couldn't find a tree builder with the features you requested: lxml. Do you need to install a parser library?

#6 楼 @raymond 太多学习的地方了👍🏻

#8 楼 @jamesparagon 把 lxml 换成 html

#9 楼 @lylyliuyu 相互学习。大家在社区互相进步

感觉吊吊的哦~~

#12 楼 @huangke 这还是基础,后面还有更屌的

支持下,回去手工自己敲敲

BeautifulSoup4 传送门点了 404 哎

感觉和第一课比起来难度陡增呢。。。运行时出了下面的 warning,还有一些乱码。我在开头加入了 #coding=utf-8 字样,不过还是有乱码,是 python2.7 的问题么?
Warning (from warnings module):
File "D:\python\lib\site-packages\beautifulsoup4-4.4.1-py2.7.egg\bs4_init_.py", line 166
UserWarning: No parser was explicitly specified, so I'm using the best available HTML parser for this system ("html.parser"). This usually isn't a problem, but if you run this code on another system, or in a different virtual environment, it may use a different parser and behave differently.

To get rid of this warning, change this:

BeautifulSoup([your markup])

to this:

BeautifulSoup([your markup], "html.parser")

('\xe8\xbf\x99\xe7\xaf\x87\xe6\x96\x87\xe7\xab\xa0\xe7\x9a\x84\xe5\x90\x8d\xe5\xad\x97\xe6\x98\xaf \xef\xbc\x9a', u'Python \u7f51\u7edc\u722c\u866b (\u4e00) ')
('\xe8\xaf\xa5\xe6\x96\x87\xe7\xab\xa0\xe5\xb1\x9e\xe4\xba\x8e \xef\xbc\x9a', u'\u5176\u4ed6\u6d4b\u8bd5\u6846\u67b6')
('\xe8\xaf\xa5\xe6\x96\x87\xe7\xab\xa0\xe7\x9a\x84\xe5\x88\x86\xe7\xb1\xbb\xe4\xb8\xba \xef\xbc\x9a ', u'tags: Python')
----------------------------------------------------------------------这里是获取所有的楼层评论----------------------------------------------------------------------

贡献下自己写的并发抓取 bilibili 闪图保存本地的爬虫,用了 requests 和 gevent 库

# coding: utf-8

import json
import time
import os

import requests

from gevent import monkey
from gevent.pool import Pool

monkey.patch_socket()


# 下载文件,保存本地
def get_image(image_url, image_name):
    file_path = os.path.join("bilibili", image_name + ".gif")
    with open(file_path, "wb") as image:
        image.write(requests.get(image_url, timeout=20).content)


# 获取下载链接和文件名
def get_image_info(bll_url):
    r = requests.get(bll_url, timeout=20)
    dict_ = json.loads(r.content)["fix"]
    return [(i["icon"], i["title"]) for i in dict_]


def download_asynchronous(url):
    time_start = time.time()
    if not os.path.exists("bilibili"):
        os.mkdir("bilibili")

    # 限制并发数
    pool = Pool(10)
    image_info = get_image_info(url)
    [pool.spawn(get_image, *(i)) for i in image_info]
    pool.join(timeout=30)
    print 'finished , used {0} s, number is {1}'.format(int(time.time() - time_start), len(image_info))
    print '-------------------------------------------------'

if __name__ == "__main__":
    url = "http://www.bilibili.com/index/index-icon.json"
    download_asynchronous(url)

#15 楼 @fengche 好的,晚一点我补一下

19楼 已删除

#15 楼 @fengche 已修改

#16 楼 @jamesparagon python2.7 里想输出中文字符,最好使用 u""这种方法
我修改了一下获取文章名称的那几行,亲测能输出中文,下面是具体代码

print(u"这篇文章的名字是 : %s "  %response.h1.string)  # 获取文章标题˜
print(u"该文章属于 :%s "  %response.find('a',{"class":"node"}).text) #获取发表在哪一个技术类型下
print(u"该文章的分类为 : %s "  %response.h2.string)

#21 楼 @y1i1n1 谢谢指导

不错,不错!

—— 来自 TesterHome 官方 安卓客户端

这个可以在 python3 下运行吗

原来第二个在这里, 继续看完.

Scrapy + gevent

发现你习惯 “,” 前敲个空格...

#27 楼 @jiagd0105 对。。。个人习惯, 虽然不符合 PEP8 但我还是保留下来了。

#28 楼 @raymond 楼主能不能留个联系方式,想交流下

抓取 googleplay 排行榜的应用信息,但返回结果中只有榜单前 60 的内容,想抓取 60 以后的内容应该怎么办呢?
代码就是第一个示例改了下 url

request_url = 'https://play.google.com/store/apps/collection/topselling_free?hl=en'
31楼 已删除
32楼 已删除


如红色框出来的部分,这样 Bs4 模块解析为何不对?求解答啊😭

yuweixx 回复

post 里传送 start =0 ,num = 100,num 数值多少你就可以爬多少

yuweixx 回复

可我爬到的总是中国排行,你能爬到美国排行么

xxNB 回复

这个跟网络有关,挂上 *** 应该就可以爬美国的了。

yuweixx 回复

是登陆问题,未登录状态抓的就是中国的,

xxNB 回复

我在连了美国的 *** 后,未登录 googleplay,抓https://play.google.com/store/apps/collection/topselling_free?hl=en
,拿到的是美国的榜单哦。

yuweixx 回复

为毛我怎么爬都是中国的榜单,好无语啊,我也连了美国地区的 *** 啊,用浏览器查看都是美国的排行,用爬虫爬却是中国的,能让我看看你的代码么,看看是不是 header 设置的有问题

xxNB 回复

你的 *** 是不是有智能分流的功能,关掉试试。

shela2009 Python 网络爬虫 (一) 中提及了此贴 08月02日 02:15
42楼 已删除
43楼 已删除
AWSL 回复

看报错信息

To get rid of this warning, change this:

BeautifulSoup([your markup])

to this:

BeautifulSoup([your markup], "html.parser")

应该就是把你代码里的 BeautifulSoup([your markup]) 改成 BeautifulSoup([your markup], "html.parser")


额。。请教我这个为什么会运行出一半报错。。

这个问题你解决了吗,怎么解决的,我也遇到了。。。

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册