Code Monkey home page Code Monkey logo

wereadscan's Introduction

WeReadScan

GitHub last commit GitHub code size in bytes GitHub top language pip

About

一个用于的将微信读书上的图书扫描转换本地PDF/HTML的爬虫库.

谈谈为何而开发

不得不说,“微信读书”是一个很好的平台。但是美中不足很明显,用户购买了图书资源,但是只能在“微信读书”的Application中阅读或者做一些文字批注╮(╯▽╰)╭,这些功能相较于购买的纸质书籍显然是不足的。比如,作者就习惯于用iPad的相关notebook类app做笔记,而“微信读书”并没有适配pencil做handwriting笔记的功能。

因此,既然“微信读书”没有提供,那只好自己解决了。于是,经过2天的开发,终于有了这个爬虫脚本,也可以开心地做手写笔记了o( ̄▽ ̄)ブ

相关版本

Sec-ant的建议下,参考了他的解决方案weread-scraper,将其中最重要的获取#preRenderContent的部分脚本进行整合,得到了WeReadScan-HTML版本,可以直接自动化获得多本图书的HTML,更加高效。

Get started

pip install WeReadScan-HTML

本项目需要使用selenium,需要对selenium具备基础的了解

Demo

话不多说,直接上代码

from selenium.webdriver import Edge
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.edge.options import Options

from WeReadScan import WeRead

options = Options()
options.add_argument("--disable-blink-features=AutomationControlled")
options.add_argument('disable-infobars')
options.add_argument('log-level=3')
options.add_argument("headless")

# launch Webdriver
print('Webdriver launching...')
driver = Edge(options=options)
# driver = Edge(service=service, options=options)
print('Webdriver launched.')

with WeRead(driver,debug=True) as weread:
    weread.login() #? login for grab the whole book
    weread.scan2html('https://weread.qq.com/web/reader/2c632ef071a486a92c60226kc81322c012c81e728d9d180')
    weread.scan2html('https://weread.qq.com/web/reader/a9c32f40717db77aa9c9171kc81322c012c81e728d9d180')

扫描结果样例:

几点说明:

  1. webdriver 需要 无头(headless) 模式启动
  2. 只有登陆后,才能扫描完整的图书资源;若不登陆,也可以扫描部分无需解锁的部分

API Reference

WeRead

WeReadScan.WeRead(headless_driver)

微信读书网页代理,用于图书扫描

Args

  • headless_driver: 设置了headless的Webdriver示例

Returns

  • WeReadInstance

Usage

chrome_options = ChromeOptions()
chrome_options.add_argument('--headless')
headless_driver = Chrome(chrome_options=chrome_options)
weread = WeRead(headless_driver)

Login

WeReadScan.WeRead.login(wait_turns=15)

展示二维码以登陆微信读书

Args

  • wait_turns: 登陆二维码等待扫描的等待轮数

Usage

weread.login()

Scan2html

WeReadScan.WeRead.scan2html(book_url, save_at='.', show_output=True)

扫面微信读书的书籍转换为PDF并保存本地

Args

参数名 类型 默认值 描述
book_url str 必填 扫描目标书籍的URL
save_at str '.' 保存地址
show_output bool True 是否在该方法函数结束时展示生成的PDF文件

Usage

weread.scan2html('https://weread.qq.com/web/reader/a57325c05c8ed3a57224187kc81322c012c81e728d9d180')

Disclaimer

  • 本脚本仅限用于已购图书的爬取,用于私人学习目的,禁止用于商业目的和网上资源扩散,尊重微信读书方面的利益
  • 若User使用该脚本用于不当的目的,责任由使用者承担,作者概不负责

Stargazers over time

Stargazers over time

wereadscan's People

Contributors

algebra-fun avatar codacy-badger avatar imgbotapp avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

wereadscan's Issues

截图不全的情况处理

使用该库时出现截图不全,经过调试后有以下几个方式可以处理:

  1. scanBook.py:若页面过长,此处需要修改浏览器选项缩放页面(原理:canvas高度与实际不匹配,缩放后才能覆盖全部,截图不全的情况出现在多个canvas的高度相加与其父节点高度不相等)
    firefox_options.set_preference("layout.css.devPixelsPerPx", "0.5")
  2. WeRead.py:shot_full_canvas_context函数高度和宽度修改
  3. png2pdf.py:PIL修改为使用reportlab转换成pdf(原理:PIL像素限制)

能生成目录吗(书签)

下载HTML后,试图转成其他格式,比如epub,pdf,显示效果很棒,但唯一不足之处就是没有书签,即可跳转的目录

截图

我也想把自己看过的书导出成pdf的可惜加密了,您的采用截图的方法很好,但是图片处理的二值化之后图像显示很差,最为关键的是截屏不完整,这是个很严重的bug

登陆后无法运行

请问扫码登陆之后出现如下的错误是什么原因呢?
StaleElementReferenceException: Message: stale element reference: stale element not found
(Session info: headless chrome=114.0.5735.199)

截图报错:Cannot take screenshot with 0 width.

环境:

chrome=105.0.5195.125
python=3.7

代码:

`
chrome_options = ChromeOptions()
chrome_options.add_argument('--headless')
chrome_options.add_argument("--disable-blink-features=AutomationControlled")
chrome_options.add_argument('disable-infobars')
chrome_options.add_argument('log-level=3')

headless_driver = Chrome(options=chrome_options)

with WeRead(headless_driver, debug=True) as weread:
weread.login()
weread.scan2pdf('https://weread.qq.com/web/reader/63b324905e0d2263b04bad7')
`

报错:

selenium.common.exceptions.WebDriverException: Message: unknown error: unhandled inspector error: {"code":-32000,"message":"Cannot take screenshot with 0 width."} (Session info: headless chrome=105.0.5195.125)

直接退出来,不知道怎么回事?运行的是demo.py

DevTools listening on ws://127.0.0.1:65223/devtools/browser/38669c9b-4e1e-4bef-9e89-201869632723
Webdriver launched.
Waiting for QRCode Scan...0/15turns
Waiting for QRCode Scan...1/15turns
Waiting for QRCode Scan...2/15turns
Login Succeed.
Scanning the book:"机器学习算法的数学解析与Python实现"
Traceback (most recent call last):
File "demo.py", line 30, in
weread.scan2html('https://weread.qq.com/web/reader/2c632ef071a486a92c60226kc81322c012c81e728d9d180')
File "C:\vnstudio\lib\site-packages\WeReadScan\WeRead.py", line 189, in scan2html
html = self.get_html(book_url)
File "C:\vnstudio\lib\site-packages\WeReadScan\WeRead.py", line 163, in get_html
readerFooterClass = readerFooter.get_attribute('class')
File "C:\Users\Administrator\AppData\Roaming\Python\Python37\site-packages\selenium\webdriver\remote\webelement.py", line 156, in get_attribute
self, name)
File "C:\Users\Administrator\AppData\Roaming\Python\Python37\site-packages\selenium\webdriver\remote\webdriver.py", line 874, in execute_script
'args': converted_args})['value']
File "C:\Users\Administrator\AppData\Roaming\Python\Python37\site-packages\selenium\webdriver\remote\webdriver.py", line 418, in execute
self.error_handler.check_response(response)
File "C:\Users\Administrator\AppData\Roaming\Python\Python37\site-packages\selenium\webdriver\remote\errorhandler.py", line 243, in check_response
raise exception_class(message, screen, stacktrace)
selenium.common.exceptions.StaleElementReferenceException: Message: stale element reference: element is not attached to the page document
(Session info: headless chrome=107.0.5304.107)
Stacktrace:
Backtrace:
Ordinal0 [0x007BACD3+2075859]
Ordinal0 [0x0074EE61+1633889]
Ordinal0 [0x0064B7BD+571325]
Ordinal0 [0x0064E374+582516]
Ordinal0 [0x0064E225+582181]
Ordinal0 [0x0064EBA5+584613]
Ordinal0 [0x006ABF4F+966479]
Ordinal0 [0x0069731C+881436]
Ordinal0 [0x006AB56A+963946]
Ordinal0 [0x00697136+880950]
Ordinal0 [0x0066FEFD+720637]
Ordinal0 [0x00670F3F+724799]
GetHandleVerifier [0x00A6EED2+2769538]
GetHandleVerifier [0x00A60D95+2711877]
GetHandleVerifier [0x0084A03A+521194]
GetHandleVerifier [0x00848DA0+516432]
Ordinal0 [0x0075682C+1665068]
Ordinal0 [0x0075B128+1683752]
Ordinal0 [0x0075B215+1683989]
Ordinal0 [0x00766484+1729668]
BaseThreadInitThunk [0x76D0FA29+25]
RtlGetAppContainerNamedObjectPath [0x76FE7A7E+286]
RtlGetAppContainerNamedObjectPath [0x76FE7A4E+238]

AttributeError: 'WeRead' object has no attribute 'scan2pdf'

运行 demo.py时报错。

Webdriver launching...
Webdriver launched.
Waiting for QRCode Scan...0/15turns
Waiting for QRCode Scan...1/15turns
Login Succeed.
Traceback (most recent call last):
  File "/Users/zec/Documents/Repos/WeReadScan/example/demo.py", line 27, in <module>
    weread.scan2pdf('https://weread.qq.com/web/reader/60b32c107207bc8960bd9cekecc32f3013eccbc87e4b62e')
AttributeError: 'WeRead' object has no attribute 'scan2pdf'

运行出错

Wait for QRCode Scan...0/15turns
Login Succeed.
Task launching...
navigate to https://weread.qq.com/web/reader/50532a905cde3050538da2b
preparing to scan "竞争战略"
scanning chapter "推荐序1"
Traceback (most recent call last):
File "/Users/zhigangyang/development/WXRead/WX.py", line 15, in
weread.scan2pdf('https://weread.qq.com/web/reader/50532a905cde3050538da2b')
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/WeReadScan/WeRead.py", line 171, in scan2pdf
self.shot_full_displayed_element(context, f'{png_name}.png')
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/WeReadScan/WeRead.py", line 60, in shot_full_displayed_element
element.screenshot(file_name)
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/selenium/webdriver/remote/webelement.py", line 585, in screenshot
png = self.screenshot_as_png
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/selenium/webdriver/remote/webelement.py", line 567, in screenshot_as_png
return base64.b64decode(self.screenshot_as_base64.encode('ascii'))
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/selenium/webdriver/remote/webelement.py", line 557, in screenshot_as_base64
return self._execute(Command.ELEMENT_SCREENSHOT)['value']
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/selenium/webdriver/remote/webelement.py", line 633, in _execute
return self._parent.execute(command, params)
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/selenium/webdriver/remote/webdriver.py", line 321, in execute
self.error_handler.check_response(response)
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/selenium/webdriver/remote/errorhandler.py", line 242, in check_response
raise exception_class(message, screen, stacktrace)
selenium.common.exceptions.WebDriverException: Message: unknown error: unhandled inspector error: {"code":-32000,"message":"Cannot take screenshot with 0 width."}

mac下报错

File "/usr/local/lib/python3.8/site-packages/WeReadScan/WeRead.py", line 171, in scan2pdf
self.shot_full_displayed_element(context, f'{png_name}.png')
File "/usr/local/lib/python3.8/site-packages/WeReadScan/WeRead.py", line 60, in shot_full_displayed_element
element.screenshot(file_name)
File "/usr/local/lib/python3.8/site-packages/selenium/webdriver/remote/webelement.py", line 585, in screenshot
png = self.screenshot_as_png
File "/usr/local/lib/python3.8/site-packages/selenium/webdriver/remote/webelement.py", line 567, in screenshot_as_png
return base64.b64decode(self.screenshot_as_base64.encode('ascii'))
File "/usr/local/lib/python3.8/site-packages/selenium/webdriver/remote/webelement.py", line 557, in screenshot_as_base64
return self._execute(Command.ELEMENT_SCREENSHOT)['value']
File "/usr/local/lib/python3.8/site-packages/selenium/webdriver/remote/webelement.py", line 633, in _execute
return self._parent.execute(command, params)
File "/usr/local/lib/python3.8/site-packages/selenium/webdriver/remote/webdriver.py", line 321, in execute
self.error_handler.check_response(response)
File "/usr/local/lib/python3.8/site-packages/selenium/webdriver/remote/errorhandler.py", line 242, in check_response
raise exception_class(message, screen, stacktrace)
selenium.common.exceptions.WebDriverException: Message: unknown error: unhandled inspector error: {"code":-32000,"message":"Cannot take screenshot with 0 width."}
(Session info: headless chrome=79.0.3945.130)

可以弹出二维码,扫码之后,scanning chapter 之后就报错啦。

png2jpg 报错

如果章节篇幅过长,该方法会报错

Maximum supported image dimension is 65500 pixels
Traceback (most recent call last):
  File "test.py", line 16, in <module>
    weread.scan2pdf('https://weread.qq.com/web/reader/d2332cf05b3a64d2302db21')
  File "/home/zhy/.local/lib/python3.6/site-packages/WeReadScan/WeRead.py", line 219, in scan2pdf
    jpg_name = png2jpg(png_name, binary_threshold, quality)
  File "/home/zhy/.local/lib/python3.6/site-packages/WeReadScan/script/png2pdf.py", line 20, in png2jpg
    # 这里
    Image.fromarray(dst).save(f'{file_name}.jpg', quality=quality)
  File "/home/zhy/.local/lib/python3.6/site-packages/PIL/Image.py", line 2164, in save
    save_handler(self, fp, filename)
  File "/home/zhy/.local/lib/python3.6/site-packages/PIL/JpegImagePlugin.py", line 761, in _save
    ImageFile._save(im, fp, [("jpeg", (0, 0) + im.size, 0, rawmode)], bufsize)
  File "/home/zhy/.local/lib/python3.6/site-packages/PIL/ImageFile.py", line 544, in _save
    raise OSError(f"encoder error {s} when writing image file")
OSError: encoder error -2 when writing image file

jpeg 规范只用了 4 字节存储像素大小,所以文件太大不行的,可以考虑直接用 png 转pdf ?

爬了一半报错了,可以有人帮我看看咋回事吗?

1663227389845

Output exceeds the size limit. Open the full output data in a text editor

ElementClickInterceptedException Traceback (most recent call last)
in
27 weread.login() #? login for grab the whole book
28 # weread.scan2pdf('https://weread.qq.com/web/reader/60b32c107207bc8960bd9cekecc32f3013eccbc87e4b62e')
---> 29 weread.scan2pdf('https://weread.qq.com/web/reader/51d329b0813ab6bccg0139b8k1c3321802231c383cd30bb3')
30

in scan2pdf(self, book_url, save_at, binary_threshold, quality, show_output, font_size_index)
272
273 # go to next page or chapter
--> 274 readerFooter.click()
275
276 print('pdf converting...')

d:\software\Anaconda\lib\site-packages\selenium\webdriver\remote\webelement.py in click(self)
78 def click(self) -> None:
79 """Clicks the element."""
---> 80 self._execute(Command.CLICK_ELEMENT)
81
82 def submit(self):

d:\software\Anaconda\lib\site-packages\selenium\webdriver\remote\webelement.py in _execute(self, command, params)
691 params = {}
692 params['id'] = self._id
...
Ordinal0 [0x00F45230+1856048]
BaseThreadInitThunk [0x7502FA29+25]
RtlGetAppContainerNamedObjectPath [0x76F67B5E+286]
RtlGetAppContainerNamedObjectPath [0x76F67B2E+238]

是否是腾讯的反爬虫?

竞争战略.pdf
降低selenium版本或者重写S函数之后,成功把demo运行起来了,并下载得到了《竞争战略》的pdf。
然而里面没有文字。如果是类似于截屏的扫描,应该有文字显示出来才对。
这个问题是否是腾讯的反爬虫?我们应该如何解决呢?
请项目主抽空看一看。
image

无法翻页问题

章节跳转到该章节的第一页时无法点击;

增加以下下代码,解决;

n = 2
while True:
.....
 # go to next page or chapter ;266行
            try:
                next_btn.click()
            except Exception:
                self.switch_to_context(tag=n + 1)
            n += 1

修改方法

 def switch_to_context(self, tag=2):
        """switch to main body of the book"""
        self.S('button.catalog').click()
        self.S(f'li.chapterItem:nth-child({tag})').click()

CSS 选择器使用了新版 Selenium 弃用的方法

Selenium 4.3.0+ 版本弃用了 WebDriver 对象的 find_element_by_* 方法,由统一的 find_element 方法替代。因此 WeRead.py 中的 CSS 选择器可能改成self.driver.find_element(By.CSS_SELECTOR, 'css_selector')比较合适,不然会报 AttributeError。

微信图书 HTML 导出脚本

我写了一个将微信读书中的(你自己能够阅览的)书籍导出为 HTML 的前端用户脚本,HTML 文件可以通过浏览器进一步打印为 PDF:https://github.com/Sec-ant/weread-scraper

效果大致如图(这个是打印成 PDF 之后):
screenshot

我对浏览器自动化测试工具了解不多,不过欢迎仓库主人参考我的方案,文本内容导出可行的情况下,相比于截图还是有很大优势的。

Running error

driver: WebDriver = Chrome(chrome_options=chrome_options)

改成:driver: WebDriver = Chrome(options=chrome_options)
可正常运行

启动 Webdriver 时 :

C:\Users\Arcti\AppData\Local\Programs\Python\Python38\python.exe C:/Users/Arcti/Desktop/WeReadScan/example/demo.py
C:/Users/Arcti/Desktop/WeReadScan/example/demo.py:23: DeprecationWarning: use options instead of chrome_options
driver: WebDriver = Chrome(chrome_options=chrome_options)
Webdriver launching...
Traceback (most recent call last):
File "C:\Users\Arcti\AppData\Local\Programs\Python\Python38\lib\site-packages\selenium\webdriver\chrome\webdriver.py", line 76, in init
RemoteWebDriver.init(
File "C:\Users\Arcti\AppData\Local\Programs\Python\Python38\lib\site-packages\selenium\webdriver\remote\webdriver.py", line 157, in init
self.start_session(capabilities, browser_profile)
File "C:\Users\Arcti\AppData\Local\Programs\Python\Python38\lib\site-packages\selenium\webdriver\remote\webdriver.py", line 252, in start_session
response = self.execute(Command.NEW_SESSION, parameters)
File "C:\Users\Arcti\AppData\Local\Programs\Python\Python38\lib\site-packages\selenium\webdriver\remote\webdriver.py", line 319, in execute
response = self.command_executor.execute(driver_command, params)
File "C:\Users\Arcti\AppData\Local\Programs\Python\Python38\lib\site-packages\selenium\webdriver\remote\remote_connection.py", line 374, in execute
return self._request(command_info[0], url, body=data)
File "C:\Users\Arcti\AppData\Local\Programs\Python\Python38\lib\site-packages\selenium\webdriver\remote\remote_connection.py", line 397, in _request
resp = self._conn.request(method, url, body=body, headers=headers)
File "C:\Users\Arcti\AppData\Local\Programs\Python\Python38\lib\site-packages\urllib3\request.py", line 79, in request
return self.request_encode_body(
File "C:\Users\Arcti\AppData\Local\Programs\Python\Python38\lib\site-packages\urllib3\request.py", line 171, in request_encode_body
return self.urlopen(method, url, **extra_kw)
File "C:\Users\Arcti\AppData\Local\Programs\Python\Python38\lib\site-packages\urllib3\poolmanager.py", line 336, in urlopen
response = conn.urlopen(method, u.request_uri, **kw)
File "C:\Users\Arcti\AppData\Local\Programs\Python\Python38\lib\site-packages\urllib3\connectionpool.py", line 670, in urlopen
httplib_response = self._make_request(
File "C:\Users\Arcti\AppData\Local\Programs\Python\Python38\lib\site-packages\urllib3\connectionpool.py", line 392, in _make_request
conn.request(method, url, **httplib_request_kw)
File "C:\Users\Arcti\AppData\Local\Programs\Python\Python38\lib\http\client.py", line 1230, in request
self._send_request(method, url, body, headers, encode_chunked)
File "C:\Users\Arcti\AppData\Local\Programs\Python\Python38\lib\http\client.py", line 1276, in _send_request
self.endheaders(body, encode_chunked=encode_chunked)
File "C:\Users\Arcti\AppData\Local\Programs\Python\Python38\lib\http\client.py", line 1225, in endheaders
self._send_output(message_body, encode_chunked=encode_chunked)
File "C:\Users\Arcti\AppData\Local\Programs\Python\Python38\lib\http\client.py", line 1004, in _send_output
self.send(msg)
File "C:\Users\Arcti\AppData\Local\Programs\Python\Python38\lib\http\client.py", line 944, in send
self.connect()
File "C:\Users\Arcti\AppData\Local\Programs\Python\Python38\lib\site-packages\urllib3\connection.py", line 187, in connect
conn = self._new_conn()
File "C:\Users\Arcti\AppData\Local\Programs\Python\Python38\lib\site-packages\urllib3\connection.py", line 159, in _new_conn
conn = connection.create_connection(
File "C:\Users\Arcti\AppData\Local\Programs\Python\Python38\lib\site-packages\urllib3\util\connection.py", line 51, in create_connection
host, port = "address"
ValueError: too many values to unpack (expected 2)

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File "C:/Users/Arcti/Desktop/WeReadScan/example/demo.py", line 23, in
driver: WebDriver = Chrome(chrome_options=chrome_options)
File "C:\Users\Arcti\AppData\Local\Programs\Python\Python38\lib\site-packages\selenium\webdriver\chrome\webdriver.py", line 83, in init
self.quit()
File "C:\Users\Arcti\AppData\Local\Programs\Python\Python38\lib\site-packages\selenium\webdriver\chrome\webdriver.py", line 158, in quit
self.service.stop()
File "C:\Users\Arcti\AppData\Local\Programs\Python\Python38\lib\site-packages\selenium\webdriver\common\service.py", line 147, in stop
if self.process is None:
AttributeError: 'Service' object has no attribute 'process'

Process finished with exit code 1

如何去设置修改这些文件?
才疏学浅,可否把文件打包成exe文件方便学习。

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.