跳转到主要内容

Scrapy模型助手,用于从模型创建爬虫

项目描述

使用Scrapy选择器创建爬虫
============================================

[![构建
状态](https://travis-ci.org/rochacbruno/scrapy_model.png)](https://travis-ci.org/rochacbruno/scrapy_model)

[![PyPi版本](https://pypip.in/v/scrapy_model/badge.png)](https://pypi.python.org/pypi/scrapy_model/)
[![PyPi下载](https://pypip.in/d/scrapy_model/badge.png)](https://pypi.python.org/pypi/scrapy_model/)

## 什么是Scrapy?

Scrapy是一个快速的高级网页抓取和爬虫框架,用于爬取网站并从其页面中提取结构化数据。它可以用于各种目的,从数据挖掘到监控和自动化测试。

https://scrapy.net.cn/


## 什么是scrapy_model?

它只是一个助手,用于使用Scrapy选择器创建爬虫,允许您通过CSS或通过XPATH选择元素,并通过模型(就像ORM模型一样)结构化您的爬虫,并通过`populate`方法将其连接到ORM模型。

导入BaseFetcherModel,CSSField或XPathField(您可以使用两者)

```python
from scrapy_model import BaseFetcherModel, CSSField
```

转到您想要抓取的网页,并使用Chrome开发者工具或Firebug找出CSS路径。假设您想从某个页面获取以下片段。

```html
<span id="person">Bruno Rocha <a href="http://brunorocha.org">网站</a></span>
```

```python
class MyFetcher(BaseFetcherModel)
name = CSSField('span#person')
website = CSSField('span#person a')
# XPathField('//xpath_selector_here')
```

字段可以接收``auto_extract=True``参数,在调用解析器或处理器之前自动从选择器中提取值。您还可以传递``takes_first=True``,它将尝试自动提取结果的第一元素,因为Scrapy选择器返回匹配元素的一个列表。


### 单个字段中的多个查询

您可以为单个字段使用多个查询

```python
name = XPathField(
['//*[@id="8"]/div[2]/div/div[2]/div[2]/ul',
'//*[@id="8"]/div[2]/div/div[3]/div[2]/ul']
)
```

在这种情况下,解析器将尝试通过第一个查询来获取数据,如果找到匹配项,则返回,否则将尝试后续查询,直到找到某个匹配项,或者返回一个空选择器。

#### 通过查询验证器找到最佳匹配

如果您想运行多个查询并验证最佳匹配,可以传递一个验证器函数,它将接收Scrapy选择器并返回一个布尔值。

例如,假设您定义了上面的“name”字段,并且想验证每个查询以确保其中包含文本“Schblaums”的“li”。

```python

def has_schblaums(selector)
for li in selector.css('li'): # 选择ul选择器内的每个<li>
li_text = li.css('::text').extract() # 仅提取文本
if "Schblaums" in li_text: # 检查是否包含“Schblaums”
return True # 返回已验证!
return False # 否则所有查询均无效

class Fetcher(....)
name = XPathField(
['//*[@id="8"]/div[2]/div/div[2]/div[2]/ul',
'//*[@id="8"]/div[2]/div/div[3]/div[2]/ul'],
query_validator=has_schblaums,
default="undefined_name" # 可选
)
```

在上面的示例中,如果两个查询都无效,则“name”字段将填充为empty_selector,或者“default”参数中定义的值。

> **注意**:如果字段有“default”并且所有匹配器都失败,则默认值将被传递到“processor”和“parse_”方法。

每个名为``parse_<field>``的方法将在每个字段的字段都获取后运行。

```python
def parse_name(self, selector)
# 这里selector是'span#person'的Scrapy选择器
name = selector.css('::text').extract()
return name

def parse_website(self, selector)
# 这里selector是'span#person a'的Scrapy选择器
website_url = selector.css('::attr(href)').extract()
return website_url

```


定义后需要运行爬虫


```python

fetcher = Myfetcher(url='http://.....') # 可选:使用cached_fetch=True将请求缓存到redis
fetcher.parse()
```

现在您可以在fetcher中迭代``_data``、``_raw_data``和属性

```python
>>> fetcher.name
<CSSField - name - Bruno Rocha>
>>> fetcher.name.value
Bruno Rocha
>>> fetcher._data
{"name": "Bruno Rocha", "website": "http://brunorocha.org"}
```

您可以填充一些对象

```python
>>> obj = MyObject()
>>> fetcher.populate(obj) # 可选:字段

>>> obj.name
Bruno Rocha
```

如果您不想在类中显式定义每个字段,可以使用JSON文件来自动化过程

```python
class MyFetcher(BaseFetcherModel)
"""将从json中加载"""

fetcher = MyFetcher(url='http://.....')
fetcher.load_mappings_from_file('path/to/file.json')
fetcher.parse()
```

在这种情况下,file.json应该是

```json
{
"name": {"css", "span#person"},
"website": {"css": "span#person a"}
}
```

您可以使用``{"xpath": "..."}``如果您更愿意使用xpath进行选择


### 解析器和处理器

对于每个字段,有两种方式来转换或规范化数据

#### 处理器

处理器是一个函数,或是一系列按给定顺序调用的函数,它将对字段值执行操作,接收原始选择器或值(取决于auto_extract和takes_first参数)。

它可以用于规范化、清洁、转换等。

示例

```python

def normalize_state(state_name)
# 查询数据库并返回第一个state对象的实例
return MyDatabase.State.Search(name=state_name).first()

def text_cleanup(state_name)
return state_name.strip().replace('-', '').lower()

class MyFetcher(BaseFetcherModel)
state = CSSField(
"#state::text",
takes_first=True,
processor=[text_cleanup, normalize_state]
)

fetcher = MyFetcher(url="http://....")
fetcher.parse()

fetcher._raw_data.state
'Sao-Paulo'
fetcher._data.state
<ORM实例 - State - São Paulo>
```

#### 解析方法

任何名为`parse_`的方法将在选择和解析的所有过程之后运行,它接收选择器或值(取决于auto_extract和该字段的take_first参数)。

示例

```python
def parse_name(self, selector)
return selector.css('::text').extract()[0].upper()
```

在上面的例子中,name字段返回原始选择器,在解析方法中,我们可以使用`css`或`xpath`构建额外的查询,并且需要从选择器中提取值,并根据需要选择第一个元素并应用所需的任何转换。

### 缓存HTML获取

为了缓存从URL获取的HTML以供未来的解析和测试,您需要指定一个缓存模型。默认情况下没有缓存,但您可以使用内置的RedisCache。

```python
from scrapy_model import RedisCache
fetcher = TestFetcher(cache_fetch=True,
cache=RedisCache,
cache_expire=1800)
```

或指定Redis客户端的参数。

> 这是python ``redis``模块的一般Redis连接

```python
fetcher = TestFetcher(cache_fetch=True,
cache=RedisCache("192.168.0.12:9200"),
cache_expire=1800)
```

您可以根据需要创建自己的缓存结构,例如:在memcached或s3中缓存HTML

缓存类只需要实现`get`和`set`方法。

```python
from boto import connect_s3

class S3Cache(object)
def __init__(self, *args, **kwargs)
connection = connect_s3(ACCESS_KEY, SECRET_KEY)
self.bucket = connection.get_bucket(BUCKET_ID)

def get(self, key)
value = self.bucket.get_key(key)
return value.get_contents_as_string() if key else None

def set(self, key, value, expire=None)
self.bucket.set_contents(key, value, expire=expire)


fetcher = MyFetcher(url="http://...",
cache_fetch=True,
cache=S3cache,
cache_expire=1800)

```

### 安装

安装简单

如果正在运行ubuntu,可能需要运行

```bash
sudo apt-get install python-scrapy
sudo apt-get install libffi-dev
sudo apt-get install python-dev
```

然后

```bash
pip install scrapy_model
```




```bash
git clone https://github.com/rochacbruno/scrapy_model
cd scrapy_model
pip install -r requirements.txt
python setup.py install
python example.py
```

示例代码以获取URL http://en.m.wikipedia.org/wiki/Guido_van_Rossum

```python
#coding: utf-8

from scrapy_model import BaseFetcherModel, CSSField, XPathField


class TestFetcher(BaseFetcherModel)
photo_url = XPathField('//*[@id="content"]/div[1]/table/tr[2]/td/a')

nationality = CSSField(
"#content > div:nth-child(1) > table > tr:nth-child(4) > td > a",
)

links = CSSField(
"#content > div:nth-child(11) > ul > li > a.external::attr(href)",
auto_extract=True
)

def parse_photo_url(self, selector)
return "http://en.m.wikipedia.org/{}".format(
selector.xpath("@href").extract()[0]
)

def parse_nationality(self, selector)
return selector.css("::text").extract()[0]

def parse_name(self, selector)
return selector.extract()[0]

def pre_parse(self, selector=None)
# 这个方法在解析之前执行
# 您可以覆盖它,请参阅文档字符串

def post_parse(self)
# 解析后执行
# 您可以在self._data上加载任何数据
# 访问self._data和self._fields以获取当前数据
# self.selector包含原始页面
# self.fetch()返回原始HTML
self._data.url = self.url


class DummyModel(object)
"""
仅用于测试,它可以是你数据库ORM中的模型
"""


if __name__ == "__main__"
from pprint import pprint

fetcher = TestFetcher(cache_fetch=True)
fetcher.url = "http://en.m.wikipedia.org/wiki/Guido_van_Rossum"

# 映射可以从json文件加载
# fetcher.load_mappings_from_file('path/to/file')
fetcher.mappings['name'] = {
"css": ("#section_0::text")
}

fetcher.parse()

打印 "Fetcher 持有数据"
打印 fetcher._data.name
打印 fetcher._data

# 如何填充一个对象
打印 "填充一个对象"
dummy = DummyModel()

fetcher.populate(dummy, fields=["name", "nationality"])
# fields 属性是可选的
打印 dummy.nationality
pprint(dummy.__dict__)

```

# 输出


```
Fetcher 持有数据
Guido van Rossum
{'links': [u'https://pythonlang.cn/~guido/',
u'http://neopythonic.blogspot.com/',
u'http://www.artima.com/weblogs/index.jsp?blogger=guido',
u'http://python-history.blogspot.com/',
u'https://pythonlang.cn/doc/essays/cp4e.html',
u'http://www.twit.tv/floss11',
u'http://www.computerworld.com.au/index.php/id;66665771',
u'http://www.stanford.edu/class/ee380/Abstracts/081105.html',
u'http://stanford-online.stanford.edu/courses/ee380/081105-ee380-300.asx'],
'name': u'Guido van Rossum',
'nationality': u'Dutch',
'photo_url': 'http://en.m.wikipedia.org//wiki/File:Guido_van_Rossum_OSCON_2006.jpg',
'url': 'http://en.m.wikipedia.org/wiki/Guido_van_Rossum'}
填充一个对象
荷兰
{'name': u'Guido van Rossum', 'nationality': u'Dutch'}
```

项目详情


下载文件

下载适用于您的平台文件。如果您不确定选择哪个,请了解更多关于 安装包 的信息。

源分布

scrapy_model-0.1.5.tar.gz (10.7 kB 查看散列)

上传时间

构建分布

scrapy_model-0.1.5-py2.py3-none-any.whl (13.1 kB 查看散列)

上传时间 Python 2 Python 3

由以下机构支持

AWS AWS 云计算和安全赞助商 Datadog Datadog 监控 Fastly Fastly CDN Google Google 下载分析 Microsoft Microsoft PSF 赞助商 Pingdom Pingdom 监控 Sentry Sentry 错误日志 StatusPage StatusPage 状态页