python 爬虫 scrapy 和 requsts 哪个快_Python 爬虫进阶:从Requests到Scrapy 学习心得 *小说下载代码示例...

今天终于部署了第一个scrapy爬虫,内心感慨万千。上周一直沉浸于使用requests的简洁直观之中,对scrapy臃肿的体系非常头痛。把两周以来从零学起的小小心得陈列如下:

Requests 入门

我是学习莫烦的爬虫基础途中,突然就在python上开了窍。强烈推荐他的爬虫教程。

目前使用爬虫是为了下载没有全文阅读选项的小说,要把整本书的单个章节全部下载下来,合并成一个文档。

Requests的流程非常人性化:先将网页的内容抓取下来

html = requests.get(url, headers=headers).text

2. 使用BeautifulSoup解析网页内容

soup = BeautifulSoup(html, features='html.parser')

3. 在soup里面用html的标签选择想要的内容,即小说某章节内容

work_contents = soup.find('div', {'id':'chapters'}).get_text(separator='\n')

4. 到这一步爬虫功能已经完工。

5. 接下来是用普通的python语法将章节内容写到本地文件(这里保存为txt格式)

with open("chapter.txt, "w", encoding="utf-8") as f:

f.writelines(work_contents)

6. 下载小说单章内容的代码已经全部完成!简单、轻松、快捷!

7. 那么,要下载多个章节怎么办呢?很简单,用for loop将上面的全部代码包裹起来,依次循环,每次更新一个章节的地址(url)以下载该章内容,同时更新文本文档名字(创建一个新文本)以写入该章内容。

pages = 12

for page in range(1, pages+1): # for loop

# some updated code

url = url + str(page) # sample code for updating url

html = ...

soup = ...

work_contents = ...

with open(f"{page}.txt","w", encoding="utf-8") as f: # sample code for updating file name

f.writelines(work_contents)

time.sleep(10) # delay the next round for 10 sec, avoid scraping too fast

8. 为了减缓爬取速度,避免被网站封禁,在抓取每个网页之间人工加上了延迟,即上面代码中的time.sleep()功能。

9. 至此,下载小说全本章节的代码也完工了!

Requests + Selenium 进阶

想爬取的网页需要登录,遇到这种情况又怎么办呢?有两种办法:

使用requests.Session.post()功能在请求网页时发送用户名和密码,可以保存coockies以保持登录状态;

或者,使用第三方神器Selemium+Katalon Recorder在firefox上模拟登录,并把cookies传送到requests.Session()中,达到登录目的。

稍微介绍一下第二种方式的流程:在代码中首先载入Selenium driver,这里使用了Chrome浏览器来模拟。再将登录页面的url传入driver.get()。

driver = webdriver.Chrome()

driver.get(url)

2. 接着打开Firefox浏览器,开启Katalon Recorder的record(录制)功能。正常输入用户名、密码,点击登录按钮,等待页面跳转。(这一步在浏览器中操作)

3. 关闭Katalon Recorder录制,点击export(导出),复制类似下面代码到python中。

driver.find_element_by_xpath().click() # sample code

driver.find_element_by_xpath().send_keys(username)

driver.find_element_by_xpath().click()

driver.find_element_by_xpath().send_keys(password)

4. 这样就完成了Selenium登录的过程,接下来是将cookies传入requests.Session()中。

cookies = driver.get_cookies()

session = requests.Session()

for cookie in cookies:

session.cookies.set(cookie['name'], cookie['value'])

5. 之后可以正常使用session.get()来请求网页,同时保持登录状态。

Scrapy 高级

熟练使用requests一周以后,我想要一次性爬取数百个网页。有几个困难,首先是当前的代码没有断点续传功能,另外为了避免网站封禁,总体等待时长已经达到了三个小时以上。

这个时候,已经封装了各种功能的Scrapy包就体现出了它的优势。看一下这个感天动地的回答吧——为啥要用scrapy代替requests或者urllib2:自动限速

尊重网站的机器人条款

处理网页有优势

自动重试

导出文件

自动缓存

然而,比起requests线性的直观体验,scrapy的入门学习坡度更抖。这里有一篇非常完美的scrapy下载小说教程小白进阶之Scrapy第一篇。

操作scrapy的流程如下:安装scrapy。我的上一篇文章涵盖了这一部分。

pip install scrapy

2. 在终端中使用 scrapy startproject 命令创建新的scrapy文件夹

scrapy startproject myspider

在项目文件夹中,scrapy已经自带了数个python文件,其中:items - 负责保存网页内容

spiders - 负责抓取网页,在此目录下建一个新的python文件来写scrapy爬虫

pipelines - 负责导出文件到本地

settings - 控制爬虫速度、自动限速、以及其它附加功能

middlewares - 本地缓存等功能

由此可以看出,scrapy将requests的功能分开了,封装到不同的文件下,更加自动化。

3. 现在正式开始使用scrapy。首先,在Item中为想要抓取的内容命名。

class MySpiderItem(scrapy.Item):

title = scrapy.Field() # sample code

contents = scrapy.Field()

pass

4. 接着,在spiders文件夹下创建一个新的python文件,例如myspider,py。在此处开始写爬虫。

首先为爬虫命名:

class MySpider(scrapy.Spider):

name = "myspider"

接着,如果是由一个或数个网址开始往下爬,则写入start_urls(是一个列表[])。

class MySpider(scrapy.Spider):

name = "myspider"

start_urls = ["url"]

假设我一共有5个网页要爬,每个网页又有数个链接,最终目标是抓取5个页面上的每个链接的内容。

我希望避免手写列表,而用for loop来组成起始网址(就像requests的做法一样)。那么,

page = 5

class MySpider(scrapy.Spider):

name = "myspider"

bash_url = url

def start_requests(self):

for i in (1, page+1):

url = self.base_url + str(i)

yield Request(url, self.parse)

这里,最后一行的yield会持续抛出Request()对当前url的解析内容(即response),然后用一个回调函数传入parse方法中。

我们接着来看parse方法。接着往下写。

def parse(self, response):

atags = BeautifulSoup(response.text, 'lxml').find_all('a', {'class':'name'})

urls = [l['href'] for l in atags]

for url in urls:

yield Request(url, callback=self.get_content)

现在,parse首先用BeautifulSoup分析了传过来的网页内容。先提取了页面上所有符合条件的标签。接着用该语句提取标签内部的url。

urls = [l['href'] for l in atags]

现在我们已经提取了单个页面上所有符合条件的url。针对每一个url,我们继续用yield抛出Request()对这些新的url的解析,其后传入下一个方法get_content()中,抓出新页面的内容。

下面是get_content()方法示例。

def get_content(self, response):

soup = BeautifulSoup(response.text, 'lxml')

item = ScrapyTeaItem()

item['title'] = soup.find('p', {'class':'family'}).get_text()

item['contents'] = soup.find('p', {'class':'name'}).get_text()

return item

看到这里,myspider.py终于和items.py联系上了。至此,爬虫已经爬完了五个网页上所有链接页面的内容,并将抓取的内容输入到items里面。

5. 现在,我们可以打开pipelines来存储items中的内容了。不过,要启用pipelines功能,我们得先打开settings.py文件,删除ITEM_PIPELINES = {前面的#号注释。

回到pipelines文件。将抓取的网页内容写入本地txt文件的代码如下。

class MySpiderPipeline(object):

def process_item(self, item, spider):

with open('myspider.txt', 'a', encoding='utf-8') as f: # "a" for append mode

f.write('\n'+ item['title'] + '\n') # one line

f.writelines(item['contents']) # multiple lines

return item

这样,保存网页内容的代码也写好了。

6. 如果想要控制爬取速度,则在settings中设置:要打开自动限速,则取消掉AUTOTHROTTLE前的#注释

要人为限速,或者设置自动限速的最低值,取消DOWNLOAD_DELAY前的#注释

7. 现在开始运行我们所写的爬虫。在终端中输入 scrapy crawl myspider 即可运行,创建的txt文档会保存在此项目的根目录下。

至此,scrapy爬虫已经成功写好!

Scrapy Cloud

scrapy还提供云端爬虫服务,免费用户可以一次运行一个爬虫。

2. 点击CREATE PROJECT(创建项目),输入项目名称

3. 进入Deploy Management页面,这里介绍Command line使用终端将本地项目传到云端

4. 在本地项目文件夹的终端中(在终端中使用cd和cd...命令来前进或后退文件夹),运行代码。

pip install shub

安装完全以后,再运行

shub login

在提示的API KEY处,输入云端页面上的API键

然后使用以下语句将本地项目推送到云端

shub deploy #加上云端页面上的id号码

如果使用BeautifulSoup,将会报错bs4包不支持

解决任何不支持的包的方法是这样的:本地已经自动新建了一个文件名为scrapinghub.yml。打开这个文件,在project下面添加。

project:

requirements:

file: requirements.txt

2. 在本项目根目录(即,scrapinghub.yml同级)创建文本文件requirements.txt

3. 打开requirements.txt,写入出问题的包的名字、版本,按照以下格式写。

beautifulsoup4==4.7.1

4. 要查看包的具体版本,在终端中输入pip show。例如。

pip show beautifulsoup4

5. 保存所有文件,再次在终端中推送项目。

shub deploy

这次应该可以成功了!

在云端运行爬虫:选择项目页面上的Run(运行)即可。

注意:

因内容长度关系,本文没有提及代码开头需要载入的python包。实际运行中如果没有载入相应的包,python会报错。

BeautifulSoup中为抓取网页内容所使用的标签也仅为示例,不同网站请使用浏览器的View Source和Inspect功能来查看具体标签。

bs4运行较慢,高级选择建议使用xpath或者scrapy selector来选取标签。

selenium速度也很慢,作为网站调试工具,会载入过多不相干的网页内容。

请保持良好的爬虫礼仪,尊重网站机器人条款、勿高速爬取造成服务器负担、爬取的内容勿做非法用途、请勿侵权。

学习之途漫漫,与君共勉!

你可能感兴趣的:(python,爬虫,scrapy,和,requsts,哪个快)