网站数据收集方法有很多,比如最基础的requests,简单几行就可以获取网页信息。使用selenium模拟网页点击可以绕过很多反爬策略,编写思路也不同于其他的方法。用scrapy框架来做的话可以清楚地进行目标拆分,并利用内置的线程池可以非常高效地获取信息。
本文以scrapy为目标,总结基础的使用方法,以供后续复习。
配置本地配置好python及pip后,使用pip install scrapy既可以安装scrapy。
基本使用 新建工程scrapy在使用时,需要在主机命令行里scrapy startproject
命令行也会提示进入example目录,并运行scrapy genspider来创建一个spider。比如运行scrapy genspider example_spider example.com,之后会在spiders文件夹下生成一个example_spider.py文件。爬虫的代码就需要写在这个文件内。
GET请求import scrapy
class ExampleSpiderSpider(scrapy.Spider):
name = 'example_spider'
allowed_domains = ['example.com']
start_urls = ['http://example.com/']
def parse(self, response):
pass
POST请求
import scrapy
class ExampleSpiderSpider(scrapy.Spider):
name = 'example_spider'
allowed_domains = ['example.com']
urls = [
'https://example.com/page/1/',
'https://example.com/page/2/',
]
def start_requests(self):
for target in urls:
#发送'Content-Type':'application/x-www-form-urlencoded'的请求
yield scrapy.FormRequest(
url=url,
formdata={'arg1':'xxx','arg2':'xxx'},
callback=self.parse,
meta={'arg1':1,'arg2':2}
)
#发送'Content-Type':'application/json'的请求
yield scrapy.Request(
url=url,
method='POST',
body = json.dumps({'arg1':'xxx','arg2':'xxx'}),
headers = {'Content-Type':'application/json'},
callback=self.parse,
meta={'arg1':1,'arg2':2}
)
def parse(self, response):
pass
需要注意的是:
- name 是爬虫名字,即spidername,之后运行需要指定这个名字。
- allowed_domains 指定允许爬取的域名,也可以不要。
- start_urls指定需要爬取哪些网站,运行时会一个一个向这些网站发请求,并将响应传给parse函数。如果需要动态生成目标网站,可以删掉这个start_urls变量,并添加一个start_requests(self)成员函数(需要使用yield scrapy.Request(url =
, callback=self.parse)作为返回值。爬虫运行时如果发现没有定义start_urls变量,则会调用这个函数。 - scrapy.Request用于发送GET请求。可以添加一个cb_kwargs参数,它接受一个字典,并可以在parse(self, response, **kwargs)中通过kwargs来获取这个字典,以实现自定义的参数传递。也可以使用meta参数,然后在parse里用response.meta获取传递的字典。
- scrapy.FormRequest用于发送POST请求,请求体放在formdata中,参数应当都是字符串类型。可以使用meta来进行参数传递(也可以用cb_kwargs? 没有测试)
这里对官方文档作以修改举例:
import scrapy
class QuotesSpider(scrapy.Spider):
name = "quotes"
def start_requests(self):
urls = [
'https://quotes.toscrape.com/page/1/',
'https://quotes.toscrape.com/page/2/',
]
for url in urls:
yield scrapy.Request(url=url, callback=self.parse, cb_kwargs={'this_url':url})
def parse(self, response, **kwargs):
page = response.url.split("/")[-2]
url = kwargs['this_url']
filename = f'quotes-{page}.html'
with open(filename, 'wb') as f:
f.write(response.body)
self.log(f'Saved file {filename}')
启动爬取
在最外层的example目录下运行scrapy crawl
再以官网文档为例:
import scrapy
class QuotesSpider(scrapy.Spider):
name = "quotes"
start_urls = [
'https://quotes.toscrape.com/page/1/',
'https://quotes.toscrape.com/page/2/',
]
def parse(self, response):
for quote in response.css('div.quote'):
yield {
'text': quote.css('span.text::text').get(),
'author': quote.css('small.author::text').get(),
'tags': quote.css('div.tags a.tag::text').getall(),
}
response.css来提取元素,其含义不言自明。也可以通过response.text获取文本信息。
这里的parse函数yield了一个字典,可以在运行时指定保存文件:scrapy crawl
对公开API继续爬取时,jl有奇效。



