HTTP Cache Headers in Django
no-store vs no-cache
no-store vs no-cache
Scrapy is a fast high-level web crawling and web scraping framework.
ref:
https://doc.scrapy.org/en/latest/
## Install
```bash
# on Ubuntu
$ sudo apt-get install libxml2-dev libxslt1-dev libffi-dev
# on Mac
$ brew install libffi
$ pip install scrapy service_identity
```
## Usage
```bash
# interative shell
# http://doc.scrapy.org/en/latest/intro/tutorial.html#trying-selectors-in-the-shell
$ scrapy shell "http://www.wendyslookbook.com/2013/09/the-frame-a-digital-glossy/"
# or
$ scrapy shell --spider=seemodel
>>> view(response)
>>> fetch(req_or_url)
# create a project
$ scrapy startproject blackwindow
# create a spider
$ scrapy genspider fancy www.fancy.com
# run spider
$ scrapy crawl fancy
$ scrapy crawl pinterest -L ERROR
```
Spider
去爬資料的程式,用 parse() 定義你要 parse 哪些資料
Item
定義抓回來的資料欄位,可以想成是 django 的 model
Pipeline
對抓回來的資料進行加工,可能是清除 html 或是檢查重複之類的
scrapy 底層是用 lxml 和 Twisted
ref:
https://github.com/vinta/BlackWidow
## Tips
### Debugging
```py
from scrapy.shell import inspect_response
inspect_response(response, self)
```
These 2 lines will invoke the interative shell.
### 相對路徑 XPath
```py
divs = response.xpath('//div')
for p in divs.xpath('.//p'): # extracts all
inside
print p.extract()
```
### Access Django Model in Scrapy
```py
def setup_django_env(django_settings_dir):
import imp
import sys
from django.core.management import setup_environ
django_project_path = os.path.abspath(os.path.join(django_settings_dir, '..'))
sys.path.append(django_project_path)
sys.path.append(django_settings_dir)
f, filename, desc = imp.find_module('settings', [django_settings_dir, ])
project = imp.load_module('settings', f, filename, desc)
setup_environ(project)
# where Django settings.py placed
DJANGO_SETTINGS_DIR = '/all_projects/heelsfetishism/heelsfetishism'
setup_django_env(DJANGO_SETTINGS_DIR)
```
then you can import Django's modules in scrapy, like this:
```py
from django.contrib.auth.models import User
from app.models import SomeModel
```
### State
http://doc.scrapy.org/en/latest/topics/jobs.html#keeping-persistent-state-between-batches
```py
def parse_item(self, response):
# parse item here
self.state['items_count'] = self.state.get('items_count', 0) + 1
```
### Close Spider
```py
from scrapy.exceptions import CloseSpider
# 只能在 spider 裡頭呼叫,不能用在 pipeline 裡
raise CloseSpider('Stop')
```
### Login in Spider
```py
from scrapy.contrib.linkextractors.sgml import SgmlLinkExtractor
from scrapy.contrib.spiders import CrawlSpider, Rule
from scrapy.http import Request, FormRequest
from blackwidow.items import HeelsItem
class SeeModelSpider(CrawlSpider):
name = 'seemodel'
allowed_domains = ['www.seemodel.com', ]
login_page = 'http://www.seemodel.com/member.php?mod=logging&action=login'
start_urls = [
'http://www.seemodel.com/forum.php?mod=forumdisplay&fid=41&filter=heat&orderby=heats',
'http://www.seemodel.com/forum.php?mod=forumdisplay&fid=42&filter=heat&orderby=heats',
]
rules = (
Rule(
SgmlLinkExtractor(allow=r'forum\.php\?mod=viewthread&tid=\d+'),
callback='parse_item',
follow=False,
),
)
def start_requests(self):
self.username = self.settings['SEEMODEL_USERNAME']
self.password = self.settings['SEEMODEL_PASSWORD']
yield Request(
url=self.login_page,
callback=self.login,
dont_filter=True,
)
def login(self, response):
return FormRequest.from_response(
response,
formname='login',
formdata={
'username': self.username,
'password': self.password,
'cookietime': 'on',
},
callback=self.check_login_response,
)
def check_login_response(self, response):
if self.username not in response.body:
self.log("Login failed")
return
self.log("Successfully logged in")
return [Request(url=url, dont_filter=True) for url in self.start_urls]
def parse_item(self, response):
item = HeelsItem()
item['comment'] = response.xpath('//*[@id="thread_subject"]/text()').extract()
item['image_urls'] = response.xpath('//ignore_js_op//img/@zoomfile').extract()
item['source_url'] = response.url
return item
```
ref:
https://doc.scrapy.org/en/latest/topics/request-response.html#topics-request-response-ref-request-userlogin
### Others
XPath 的選擇節點語法
http://mi.hosp.ncku.edu.tw/km/index.php/dotnet/48-netdisk/57-xml-xpath
Avoiding getting banned
http://doc.scrapy.org/en/latest/topics/practices.html#avoiding-getting-banned
Python 抓取框架:Scrapy 的架构
http://biaodianfu.com/scrapy-architecture.html
Download images
https://scrapy.readthedocs.org/en/latest/topics/images.html
Use dateutil and moment.js
Sending emails with Amazon SES, Mailgun, Zoho, or Gmail in Django.
使用 MIMEApplication 並設置 attachment 的 header 不然如果檔名有中文的話 用 Gmail 收到的附件檔名會是 noname def withdraw_send_email(request, pk): withdraw = get_object_or_404(Withdraw, pk=pk) email = '[email protected]' subject = _(u'Packer 數位發行服務') body = render_to_string('dps/email/withdraw_notice.html', {}) message = EmailMessage( subject=subject, body=body, to=[email, ], ) message.content_subtype = 'html' from email.mime.application import MIMEApplication # 檔名包含中文的話,要用這種方式 Gmail 收到的附件檔名才不會是 noname filename = '%s 結算表.xlsx' % (withdraw.serial_number[:6].encode('utf-8'))… Read More