page_partten和item_partten编写规则 - ShichaoMa/structure_spider GitHub Wiki
page_partten
现代的web网页中,翻页策略千变万化,框架的功能很难完全支持,目前框架支持4种翻页策略,几乎可以满足90%以上网站的使用
使用xpath翻页
使用xpath直接将网页中下一页的url匹配出来,这种方式最为常见,一些比较简单的网站会使用这种方式。此类情况一般是分类页响应时html中就已经包含下一页的链接信息,所以实现起来最容易。有些网站xpath可能会经常变来变去,所以这种策略支持同时配置多个xpath,不管变成什么样,总有一款适合你,不用担心会抓取重复,框架已实现了去重功能,
demo如下
page_partten = (
'//*[@id="page-content"]//a[@rel="next"]/@href', # 翻页表达式
... # 如果翻页表达式为xpath,则可以定义多个表达式,所得到的结果为所有xpath结果的总和,也就是说xpath匹配到多少下一页链接,就会去重之后生成多少下一页任务请求
)
通过在链接后面加参数实现翻页
demo如下
page_partten = (
r'(.*?)(p=1)(\d+)(.*)', # 翻页表达式
),
有必要解释一下这个翻页表达式(正则表达式):
- 第一组匹配url分页参数前面的部分(不需要修改)
- 第二组匹配分页参数的名字+等号+起始页的页序数(这个要改,比如你的网站翻页是通过增加page参数来实现的,那么这里面就是page=,后面的数字代表你当前是第几页,如果下一页是page=2,那么这个数字填1,如果下一页page=3,那么这个数字填2)
- 第三组匹配当前页数(不需要修改)
- 第四组匹配分页参数后来的值(不需要修改) 比如http://www.nike.com/abc,第二页为http://www.nike.com/abc?pn=1,第三页为http://www.nike.com/abc?pn=2。
通过在链接后面加起始项目序号来实现翻页
demo如下
page_partten = (
'start=0',
),
配置很简单,start的意思是指标记item开始的那个参数,比如有些网站,第一页没有start,第二页变成了start=30,第三页变成了start=60,以此类推你只要把这个参数名称配置上,就可以了。比如http://www.ecco.com/abc,第二页为http://www.ecco.com/abc?start=30,第三页为http://www.ecco.com/abc?start=60。start=后面的数字是指当前页的第一项的是从所有项的第几项,一般来说是0,但有可能有特殊情况
将页数直接嵌入url中来实现翻页
demo如下
'timberland': [
r'1~=(/page/)(\d+)(/)',
- 其中{first_page_num}~={regex}用来标明该url是用url中某一部分自增来进行翻页
- ~=前面代表该分类第一页若是缺省页面,是从第几页开始计算
- ~=后面为正则表达式
- 第一组用来匹配自增数字前面可能存在的部分(可为空)
- 第二组用来匹配自增数字
- 第三组来匹配自增数字后面可能存在的部分(可为空) 比如 http://www.timberland.com.hk/en/men-apparel-shirts,他的第二页变成了http://www.timberland.com.hk/en/men-apparel-shirts/page/2/,那么其中第一组就是/page/, 第二组是2(缺省页+1), 第三组是/。
对于以上无法解决的翻页,可以通过重写page_url来解决
demo如下:
def page_url(self, response):
"""
传入response, 返回下一页的链接
"""
next_page_url = "http://music.baidu.com/data/user/getsongs"
query = urldecode(urlparse(response.url).query)
query.setdefault("ting_uid", re_search(r"artist/(\d+)", response.url))
query.setdefault("hotmax", re_search(r"var hotbarMax = (\d+)", response.body))
query["order"] = "hot"
query[".r"] = str(random.random()) + str(int(time.time() * 1000))
query.setdefault("pay", "")
return "%s?%s" % (next_page_url, urlencode(query))
item_partten
几乎所有的网页都可以通过xpath来获取item(分类页上的所有项目)
demo
item_pattern = ('//span[@class="song-title "]/a[1]/@href',)
如果实在无法获取,可以能过重写extract_item_urls获取
def extract_item_urls(self, response):
"""
传入response, 返回item的链接
"""
try:
html = safely_json_loads(response.body)['data']["html"]
except Exception:
html = response.body
sel = Selector(text=html)
return [response.urljoin(x) for x in set(sel.xpath("|".join(self.item_pattern)).extract())]
例子中给出的是百度mp3网站抓取音乐项的方法。百度mp3第一页面可以直接通过配置item_pattern来获取,正如上一节所讲,百度第二页是通过ajax获取的,所以返回的数据是json格式,这与第一页不同,因此直接无法通过一个xpath_partten获取,因为返回数据中包含一个html属性才是真正的页面数据。通过重写extract_item_urls,对第一页和第二页分别抽取item连接。